关于 C++ 拷贝构造函数(copy constructor)中的形参必须为引用类型的详解

     在《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)。。。。程序崩溃。。。。

 

posted @ 2014-12-31 11:51  Leongs'  阅读(2200)  评论(0编辑  收藏  举报