标签:
在《C++ primer》中文第四版中,关于拷贝构造函数(也称复制构造函数)是这样定义的:是一种特殊构造函数,具有单个形参,该形参(常用const修饰)是对该类类型的引用。
问题来了!为什么形参必须为该类类型的引用?而不能是值传递方式?(PS:其实传值和传址都可以统一为传值,前者传的是对象的值,后者传的是对象的地址的值)
先看下边两组代码:
1、
1 class Example { 2 3 public: 4 5 Example() {} 6 7 Example(const Example& ex) {} //拷贝构造函数,函数体为空 8 9 void test (Example param) {} //test成员函数 10 11 };
2、
1 class Example { 2 3 public: 4 5 Example() {} 6 7 Example(const Example ex) {} //拷贝构造函数,函数体为空 8 9 void test (Example param) {} //test成员函数 10 11 };
可以看出:1与2的区别在于第7行的拷贝构造函数。事实上,在VS或GCC下,2中的Example类是无法编译通过的,会报错。原因就是其形参类型为非引用类型。
那么,2中第7行定义的拷贝构造函数在实际中会发生或导致什么问题呢?就是无穷递归。(PS:这里的递归与普通的递归还有些区别:普通的递归会有基准情形,即递归可以终止。而这里的递归无基准情形,则会无穷递归下去)
为了清楚的说明这个问题,我们假设2中的代码能够通过编译,进行如下测试,看看会发生什么:
3、
1 int main () { 2 3 Example obj; //定义一个Example类的对象obj 4 5 test(obj); //调用test成员函数 6 7 return 0; 8 9 10 }
3中的第3行定义了一个Example类的对象,然后调用test函数。
即test(obj); 因为test的形参为值传递方式
test的原型为:
void test (Example param) ;
所以在执行函数体之前,会发生实参到形参的拷贝,
即 Example param(obj);
但
Example param(obj)这一步,其本身也是一个函数,只不过它是特殊的拷贝构造函数而已,其原型为 Example(const Example ex) ;
那么按照2代码中对Example类的定义,其拷贝构造函数的形参是传值方式传递的,所以会发生实参到形参的拷贝,即 Example ex(obj);obj到ex的拷贝
接着还会调用拷贝构造函数,为了方便说明,这一次的拷贝构造函数原型为: Example(const Example ex1) ;
则会发生:Example ex1(obj);obj到ex1的拷贝
同理,如此下去,还会有
Example ex2(obj),
Example ex3(obj),
.......,
Example exn(obj),
...........
子子孙孙无穷匮也。
最终会导致栈溢出(stackoverflow)。。。。程序崩溃。。。。
关于 C++ 拷贝构造函数(copy constructor)中的形参必须为引用类型的详解
标签:
原文地址:http://www.cnblogs.com/michaelleong/p/4195417.html