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的疑问的更多相关文章

  1. 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板

    [源码下载] 不可或缺 Windows Native (19) - C++: 对象的动态创建和释放, 对象的赋值和复制, 静态属性和静态函数, 类模板 作者:webabcd 介绍不可或缺 Window ...

  2. (63)Wangdao.com第十天_预处理、预解析_函数 上下文对象、参数列表对象

    预解析.预处理 1. 在全局代码执行之前,js 引擎 就会创建一个栈来存储管理所有的 执行上下文对象 2. 在 全局执行上下文 window 确定以后,进行压栈 3. 在 函数执行上下文对象 确定以后 ...

  3. C++ 数组操作符重载、函数对象分析、赋值操作符

    string类型访问单个字符 #include <iostream> #include <string> #include <sstream> using name ...

  4. 你不知道的JavaScript--Item6 var预解析与函数声明提升(hoist )

    1.var 变量预编译 JavaScript 的语法和 C .Java.C# 类似,统称为 C 类语法.有过 C 或 Java 编程经验的同学应该对"先声明.后使用"的规则很熟悉, ...

  5. python 学习笔记3(循环方式;list初始化;循环对象/生成器/表推导;函数对象;异常处理)

    ### Python的强大很大一部分原因在于,它提供有很多已经写好的,可以现成用的对象 16. 循环方式笔记: 1)range(0, 8, 2)   #(上限,下限,步长)  可以实现对元素或者下标的 ...

  6. python之三元表达式,列表|字典推导式,函数对象

    #### 三元表达式: 就是if....else...的语法糖 # -- 1) 只能解决if...else...结构,其他if分支结构都不管 # -- 2)一个分支提供一个结果: 如果一个分支提供了多 ...

  7. Atitit dsl对于数组的处理以及main函数的参数赋值

    Atitit dsl对于数组的处理以及main函数的参数赋值 1.1. 词法解析..添加了[] 方括号的解析支持1 1.2. Ast建立.添加了数组参数的支持..使用了递归下降法..getparam ...

  8. Python进阶07 函数对象

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函数也是一个对象 ...

  9. python 函数对象(函数式编程 lambda、map、filter、reduce)、闭包(closure)

    1.函数对象 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 秉承着一切皆对象的理念,我们再次回头来看函数(function).函 ...

随机推荐

  1. 如何指定rman下的备份路径

    如果不想使用缺省路径,可以以如下方式来指定: RMAN> configure channel 1 device type disk format '/rman/bak/%F';RMAN> ...

  2. [BZOJ3678]wangxz与OJ-[Splay一类的平衡树]

    Description 传送门 Solution 直接splay搞定吧..似乎非旋treap也ok? 我已经菜到模板题都写不出来了qaq Code #include<iostream> # ...

  3. 2018.10.17校内模拟赛:T2神光

    题面:pdf 首先排序,二分,然后怎么判定是否可行. 最简单的思路是,dp[i][j][k],到第i个,用了j次红光,k次绿光,前i个点都选上了,是否可行.然后转移就行. 然后考试的时候就想到这了,往 ...

  4. Java 中的正则(Pattern)

    /**String 中 replaceAll(),matches(),split() 等方法,都是调用Pattern中的方法.学习了,瞬间觉得Pattern强大了 public String repl ...

  5. 海思NB-IOT的SDK函数使用说明

    1. 查询当前AT指令是否正在处理中 while(get_at_cmd_in_progress() == false); 2. 信号量发送函数 (, osNoWait); 3. 信号量接收函数 if( ...

  6. 四、利用EnterpriseFrameWork快速开发基于WCF为中间件的三层结构系统

    回<[开源]EnterpriseFrameWork框架系列文章索引> EnterpriseFrameWork框架实例源代码下载: 实例下载 本章内容与上一张<利用Enterprise ...

  7. php实现图形计算器

    存档: index.php <html> <head> <title>图形计算器开发</title> <meta http-equiv=" ...

  8. 用树莓派Raspberry Pi和Micro:bit做一个自拍器

    在这个项目中,我们将使用Python来构建一个由Micro:bit触发树莓派Raspberry Pi和相机模块的自拍器.这是开始使用硬件和简单文本编程的好方法. 我们将学习: 如何设置Raspberr ...

  9. 4星|《财经》2018年第13期:年轻人大多从大三和大四起开始就从QQ向微信转移

    <财经>2018年第13期 总第530期 旬刊 本期主要话题是快递业,其他我感兴趣的重要话题还有:香港9价HPV疫苗断供风波:华盛顿邮报被贝佐斯收购后这几年的变化:北京二中朝阳学校的划片风 ...

  10. 生成dataset的几种方式

    1.常用的方式通过sparksession读取外部文件或者数据生成dataset(这里就不讲了)  注: 生成Row对象的方法提一下:RowFactory.create(x,y,z),取Row中的数据 ...