C++解析(19):函数对象、关于赋值和string的疑问
0.目录
1.函数对象
2.重载赋值操作符
3.string类
4.小结
1.函数对象
编写一个函数:
- 函数可以获取斐波那契数列每项的值
- 每调用一次返回一个值
- 函数可根据需要重复使用
实现功能:
#include <iostream>
#include <string>
using namespace std;
int fib()
{
static int a0 = 0;
static int a1 = 1;
int ret = a1;
a1 = a0 + a1;
a0 = ret;
return ret;
}
int main()
{
for(int i=0; i<10; i++)
{
cout << fib() << endl;
}
cout << endl;
for(int i=0; i<5; i++)
{
cout << fib() << endl;
}
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
存在的问题——函数一旦开始调用就无法重来:
- 静态局部变量处于函数内部,外界无法改变
- 函数为全局函数,是唯一的,无法多次独立使用
- 无法指定某个具体的数列项作为初始值
函数对象:
- 使用具体的类对象取代函数
- 该类的对象具备函数调用的行为三个字
- 构造函数指定具体数列项的起始位置
- 多个对象相互独立的求解数列项
函数调用操作符(( )):
只能通过类的成员函数重载
可以定义不同参数的多个重载函数
最终解决方案——把类的对象当作函数使用:
#include <iostream>
#include <string>
using namespace std;
class Fib
{
int a0;
int a1;
public:
Fib()
{
a0 = 0;
a1 = 1;
}
Fib(int n)
{
a0 = 0;
a1 = 1;
for(int i=2; i<=n; i++)
{
int t = a1;
a1 = a0 + a1;
a0 = t;
}
}
int operator () ()
{
int ret = a1;
a1 = a0 + a1;
a0 = ret;
return ret;
}
};
int main()
{
Fib fib;
for(int i=0; i<10; i++)
{
cout << fib() << endl;
}
cout << endl;
for(int i=0; i<5; i++)
{
cout << fib() << endl;
}
cout << endl;
Fib fib2(10);
for(int i=0; i<5; i++)
{
cout << fib2() << endl;
}
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
55
89
144
233
377
2.重载赋值操作符
什么时候需要重载赋值操作符?编译器是否提供默认的赋值操作?
- 编译器为每个类默认重载了赋值操作符
- 默认的赋值操作符仅完成浅拷贝
- 当需要进行深拷贝时必须重载赋值操作符
- 赋值操作符与拷贝构造函数有相同的存在意义
示例:
#include <iostream>
#include <string>
using namespace std;
class Test
{
int* m_pointer;
public:
Test()
{
m_pointer = NULL;
}
Test(int i)
{
m_pointer = new int(i);
}
Test(const Test& obj)
{
m_pointer = new int(*obj.m_pointer);
}
Test& operator = (const Test& obj)
{
if( this != &obj )
{
delete m_pointer;
m_pointer = new int(*obj.m_pointer);
}
return *this;
}
void print()
{
cout << "m_pointer = " << hex << m_pointer << endl;
}
~Test()
{
delete m_pointer;
}
};
int main()
{
Test t1 = 1;
Test t2;
t2 = t1;
t1.print();
t2.print();
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
m_pointer = 0x252f010
m_pointer = 0x252f030
(在C语言中支持自赋值,于是C++为了兼容C语言,也得支持自赋值。于是在重载赋值操作符的时候,也得处理自赋值的情况。)
问题分析:
一般性原则:
重载赋值操作符,必然需要实现深拷贝!!!
编译器默认提供的函数:
3.string类
下面的代码输出什么?为什么?
示例:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = "12345";
const char* p = s.c_str();
cout << p << endl;
s.append("abced"); // p 成为了野指针
cout << p << endl;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
12345
12345
问题分析:
下面的程序输出什么?为什么?
示例:
#include <iostream>
#include <string>
using namespace std;
int main()
{
const char* p = "12345";
string s = "";
s.reserve(10);
// 不要使用 C 语言中的方式操作 C++ 中的字符串
for(int i=0; i<5; i++)
{
s[i] = p[i];
}
cout << s << endl;
for(int i=0; i<5; i++)
{
cout << s[i] << endl;
}
return 0;
}
运行结果为空:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
1
2
3
4
5
问题分析:
改进后:
#include <iostream>
#include <string>
using namespace std;
int main()
{
const char* p = "12345";
string s = "";
s = p;
cout << s << endl;
return 0;
}
运行结果为:
[root@bogon Desktop]# g++ test.cpp
[root@bogon Desktop]# ./a.out
12345
4.小结
- 函数调用操作符(( ))是可重载的
- 函数调用操作符只能通过类的成员函数重载
- 函数调用操作符可以定义不同参数的多个重载函数
- 函数对象用于在工程中取代函数指针
- 在需要进行深拷贝的时候必须重载赋值操作符
- 赋值操作符和拷贝构造函数有同等重要的意义
- string类通过一个数据空间保存字符数据
- string类通过一个成员变量保存当前字符串的长度
- C++开发时尽量避开C语言中惯用的编程思想
C++解析(19):函数对象、关于赋值和string的疑问的更多相关文章
- 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板
[源码下载] 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板 作者:webabcd 介绍不可或缺 Window ...
- (63)Wangdao.com第十天_预处理、预解析_函数 上下文对象、参数列表对象
预解析.预处理 1. 在全局代码执行之前,js 引擎 就会创建一个栈来存储管理所有的 执行上下文对象 2. 在 全局执行上下文 window 确定以后,进行压栈 3. 在 函数执行上下文对象 确定以后 ...
- C++ 数组操作符重载、函数对象分析、赋值操作符
string类型访问单个字符 #include <iostream> #include <string> #include <sstream> using name ...
- 你不知道的JavaScript--Item6 var预解析与函数声明提升(hoist )
1.var 变量预编译 JavaScript 的语法和 C .Java.C# 类似,统称为 C 类语法.有过 C 或 Java 编程经验的同学应该对"先声明.后使用"的规则很熟悉, ...
- python 学习笔记3(循环方式;list初始化;循环对象/生成器/表推导;函数对象;异常处理)
### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 16. 循环方式笔记: 1)range(0, 8, 2) #(上限,下限,步长) 可以实现对元素或者下标的 ...
- python之三元表达式,列表|字典推导式,函数对象
#### 三元表达式: 就是if....else...的语法糖 # -- 1) 只能解决if...else...结构,其他if分支结构都不管 # -- 2)一个分支提供一个结果: 如果一个分支提供了多 ...
- Atitit dsl对于数组的处理以及main函数的参数赋值
Atitit dsl对于数组的处理以及main函数的参数赋值 1.1. 词法解析..添加了[] 方括号的解析支持1 1.2. Ast建立.添加了数组参数的支持..使用了递归下降法..getparam ...
- Python进阶07 函数对象
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函数也是一个对象 ...
- python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)
1.函数对象 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函 ...
随机推荐
- 1071: [SCOI2007]组队
1071: [SCOI2007]组队 https://lydsy.com/JudgeOnline/problem.php?id=1071 分析: dp+单调性. A*(hi–minH)+B*(si–m ...
- gitlab在push代码的时候报错
一.问题报错 gitlab在执行git pull origin master,拉取代码的时候报如下错误. $ git pull origin master remote: Counting objec ...
- 安装支持elasticsearch使用sql查询插件
一.ElasticSearch-SQL介绍 ElasticSearch-SQL(后续简称es-sql)是ElasticSearch的一个插件,提供了es 的类sql查询的相关接口.支持绝大多数的sql ...
- Drupal7 配置多站点及为每个站点设置语言
默认情况 在Drupal7的安装目录下存在sites目录 sites目录结构如下: --all --default --example.sites.php --README.txt 1. 添加新域名, ...
- 关于网易云验证码V1.0版本的服务介绍
服务介绍 易盾验证码是一个用于区分人和机器的通用验证码组件.传统的字符型验证码由于存在破解率高,用户体验不友好等问题,已不适用于现今的互联网环境.易盾验证码抛弃了传统字符型验证码展示-填写字符-比对答 ...
- exe4j 使用记录(一):下载、安装及注册
一.下载 exe4j下载地址:https://www.ej-technologies.com/download/exe4j/files 进入下载页面,可以选择exe4j版本. 选择完成后,下载即可. ...
- Windows下Mongodb安装部署
1.下载安装包 mongodb-win32-x86_64-enterprise-windows-64-3.6.4.zip 解压 安装失败(当前环境windows server2012 R2):已验证可 ...
- 不相交集合ADT -数据结构(C语言实现)
读数据结构与算法分析 不相交集合 等价关系 满足三个性质 - 自反性 - 对称性 - 传递性 基本数据结构 基本思路 使用一个数组,下标表示该集合,内容表示指向的父亲 实现 类型声明 typedef ...
- NUMA 体系架构
NUMA 体系架构 SMP 体系架构 NUMA 体系架构 NUMA 结构基本概念 Openstack flavor NUMA 策略 Nova 实现 NUMA 流程 1. SMP 体系架构 CPU 计算 ...
- SAP(ABAP) ABAP内部外部数据转换常用function
文本相关CONVERSION_EXIT_CUNIT_OUTPUT 将内部单位转为单位文本CONVERSION_EXIT_ISOLA_OUTPUT 根据语言代码取文本CONVERSI ...