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).函 ... 
随机推荐
- Twitter推广消息可使品牌线下销售额增长三成
			新浪科技讯 北京时间8月9日上午消息,Twitter周四宣布,该公司的推广消息(Promoted Tweet)可以让品牌的线下销售增长29%. 此外,Twitter当天还推出了一个新项目,让品牌可以追 ... 
- 使用 Sublime Text 做 Javascript 编辑器 - 集成 JSHint 问题检测工具
			JSHint(jshint.com)是 Javascritp 代码质量工具,可以帮助开发人员发现 Javascript 代码中的错误和潜在的问题.jshint.com 是一个在线编辑器,我们可以为 S ... 
- USACO 1.2.3  Name That Number 命名那个数字(打开文件)
			Description 在威斯康辛州牛大农场经营者之中,都习惯于请会计部门用连续数字给母牛打上烙印.但是,母牛用手机时并没感到这个系统的便利,它们更喜欢用它们喜欢的名字来呼叫它们的同伴,而不是用像这个 ... 
- 2016-6-2-第二个sprint
			1.开始一个新的冲刺: 起止:2016.6.1~2016.6.14 ProductBacklog:继续向下细化 Sprint 计划会议:确定此次冲刺要完成的目标 Sprint Backlog:新的冲刺 ... 
- Scrum立会报告+燃尽图(十月二十日总第十一次)
			此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2246 项目地址:https://git.coding.net/zhang ... 
- 王者荣耀交流协会第四次Scrum立会
			会议时间:2017年10月23号 18:00-18:28,时长28分钟. 会议地点:二食堂一楼第四个档口对着的靠路边的桌子. 立会内容: 1.小组成员汇报今日工作: 2.关于折线图与饼状图生成问题 ... 
- 2018-2019-20172321 《Java软件结构与数据结构》第四周学习总结
			2018-2019-20172321 <Java软件结构与数据结构>第四周学习总结 教材学习内容总结 第六章 6.1列表集合 列表集合是一种概念性表示法,其思想是使事物以线性列表的方式进行 ... 
- 第四周 实验一  Java开发环境的熟悉 报告
			Java开发环境的熟悉 实验内容 1.IDEA的安装过程 2.使用IDEA代替虚拟机运行.编译.调试Java程序 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)&g ... 
- 第一个scrum会议
			第一阶段冲刺任务认领: PM薛哥: 让手电筒亮起来 梁哥: 代码测试 康哥: 用户反馈等等 
- Alpha 冲刺(8/10)
			队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ... 
