关于c++中不允许复制构造函数传值参数的理解
来源:互联网 发布:查看网络延时命令 编辑:程序博客网 时间:2024/06/05 08:02
问题源于看剑指offer上的一道面试题,题目如下:
class A{private: int value;public: A(int n){ value = n; } A(A other){ value = other.value; } void Print() {cout<<value<<endl; }};int main(void){ A a = 10; A b = a; b.Print(); return 0;}
对上面这段代码进行分析编译运行的结果是:
A、编译错误 B、编译成功,运行时程序崩溃 C、编译运行正常,输出10
答案:A、编译错误。复制构造函数A(Aother)传入的参数是A的一个实例。由于是传值参数,我们把形参复制到实参会调用复制构造函数。因此如果允许复制构造函数传值,就会在复制构造函数内调用复制构造函数,就会形成永无休止的递归调用从而导致栈溢出。
敲黑板划重点:C++的标准不允许复制构造函数传值参数,只能将构造函数修改为A(const A& other),也就是把传值参数改为常量引用。(注意:传指针也是不可以的,只能改为引用)。
一开始不理解为什么会无限循环递归下去这个过程。于是在网上查了一下。用下面这个例子来深入理解一下这个过程。
#include<iostream>usingnamespace std;class CExample{private: int m_nTest;public: CExample(int x) : m_nTest(x) //带参数构造函数 { cout << "constructor withargument"<<endl; } // 拷贝构造函数,参数中的const不是严格必须的,但引用符号是必须的 CExample(const CExample & ex) //拷贝构造函数 { m_nTest = ex.m_nTest; cout << "copyconstructor"<<endl; } CExample& operator = (const CExample&ex) //赋值函数(赋值运算符重载) { cout << "assignmentoperator"<<endl; m_nTest = ex.m_nTest; return *this; } void myTestFunc(CExample ex) { }};int main(void){ CExample aaa(2); CExample bbb(3); bbb = aaa; CExample ccc = aaa; bbb.myTestFunc(aaa); return 0;}
这段代码运行后输出如下:
constructorwith argument
constructorwith argument
assignmentoperator
copyconstructor
copyconstructor
程序分解分析:
第一个constructorwith argument,来源于CExample aaa(2);因为要对aaa实例化并初始化,所以要调用带参数的构造函数
第二个constructorwith argument,来源于CExample bbb(3);同理。
assignmentoperator,来源于bbb =aaa;
第一个copyconstructor,来源于CExample ccc = aaa;这个和上面为什么有区别呢?原因是因为bbb对象已经实例化了,不需要构造,所以将aaa赋值给bbb,只会调用赋值函数。但是ccc还没有实例化,因此调用的是拷贝构造函数,构造出ccc,而不是赋值函数。
第二个copyconstructor,来源于bbb.myTestFunc(aaa);。过程是这样:首先将aaa作为参数传递给bbb.myTestFunc(CExample ex),即CExample ex = aaa;和上面一样,所以还是拷贝赋值函数。
如果拷贝构造函数是传值而不是传引用,当调用ccc.CExample(aaa)时,aaa作为参数传值给ccc.CExample(CExample ex),即CExample ex = aaa,因为ex没有被初始化,所以会继续调用拷贝构造函数,接下来是构造ex,也就是ex.CExample(aaa),必然又会有aaa传给CExample(CExample ex),即CExample ex = aaa;那么又会触发拷贝构造函数,这样就无限递归下去了。
所以,拷贝构造函数的参数使用引用类型不是为了减少一次内存拷贝,而是避免拷贝构造函数无限制的递归下去。
下面这几种情况下会调用拷贝构造函数
(1)显式或隐式地用同类型的一个对象来初始化另外一个对象。如上例中的CExample ccc = aaa;
(2)作为实参传递给一个函数。如上例中的bbb.myTestFunc(aaa);
(3)在函数体内返回一个对象时,也会调用返回值类型的拷贝构造函数
(4)初始化序列容器中的元素时。比如vector<string> svec(5),string的缺省构造函数和拷贝构造函数都会被调用。
(5)用列表的方式初始化数组元素时。string a[] = {string(“hello”),string(“world”)};会调用string的拷贝构造函数。
- 关于c++中不允许复制构造函数传值参数的理解
- C++的标准不允许复制构造函数传值参数
- 关于构造函数传递参数的理解
- 复制构造函数的理解
- 复制构造函数的理解
- 关于对于C语言中主函数参数接返回值的理解
- 构造函数,析构函数,复制构造函数的理解
- Android 中关于SimpleAdapter构造参数的理解
- 不允许拷贝构造函数传值参数,而必须是传引用或者常量引用
- 复制构造函数的参数能否采用值传递
- 对于拷贝构造函数中参数是引用的理解
- 关于构造函数的理解
- 构造函数和复制构造函数的理解与应用
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 关于复制构造函数
- 深入理解JVM之基本构架
- ROS入门记录 [3]
- mysql:The user specified as a definer ('xxx'@'%') does not exist 解决方法
- java线程系列---Runnable和Thread的区别
- C语言复习笔记 12
- 关于c++中不允许复制构造函数传值参数的理解
- 数值统计 HDU
- 83. Remove Duplicates from Sorted List
- Map集合
- (不推荐使用)springMVC基本配置+controller层实现Controller接口
- Android 7.0 FileProvider 使用说明
- CRC原理简述
- kylin入门到实战:入门
- selenium环境安装、使用