8.6 复制构造函数

    C++中经常使用一个常量或变量初始化另一个变量,如下所示。


    double x=5.0; double y=x;

    使用类创建对象时,构造函数被自动调用以完成对象的初始化,那么能否像简单变量的初始化一样,直接用一个对象来初始化另一个对象呢?答案是肯定的,以代码8.5中定义的point类为例。


    point pt1(2,3); point pt2=pt1;后一个语句也可写成如下形式。 point pt2(pt1);上述语句用pt1初始化pt2,相当于将pt1中每个数据成员的值复制到pt2中,这是表面现象,实际上,系统调用了一个复制构造函数。如果类定义中没有显式定义该复制构造函数时,编译器会隐式定义一个默认的复制构造函数,它是一个inline或public的成员函数,其原型形式如下所示。 point:point(const point&);

    复制构造函数与构造函数的不同之处在于形参,复制构造函数是本类对象的引用,其功能是将一个对象的每一个成员复制到另一个对象对应的成员当中,默认的构造函数相当于内存块的复制。需要注意的是形参中的const并非是必须的,但是推荐使用它,这样可避免对参数对象的修改。

    当然,也可以显式定义复制构造函数以完成其他的操作。在有些情况下,系统提供的默认复制构造函数足以满足需要,自行定义该函数似乎没有必要,比如代码8.5中定义的point类。但在另外一些时候,则必须要显式定义构造函数,比如代码8.8中的computer类,这两个类有什么不同呢?答案马上揭晓。

    注意

    一旦程序员显式定义了复制构造函数,编译器便不再会自动提供默认的复制构造函数。

    8.6.1 复制构造函数调用机制

    复制构造函数的调用示例如代码8.9所示。

    代码8.9 复制构造函数调用机制CopyConstructor


    <——————————————-文件名:point.h————————————————> 01 #include<iostream> 02 using namespace std; 03 class point 04 { 05 private: 06 int xPos; 07 int yPos; 08 public: 09 point(int x=0,int y=0) 10 { 11 cout<<"调用构造函数"<<endl; 12 xPos=x; 13 yPos=y; 14 } 15 point(const point&pt)//复制构造函数的定义及实现 16 { 17 cout<<"调用复制构造函数"<<endl; 18 xPos=pt. xPos; 19 yPos=pt. yPos; 20 } 21 void print() 22 { 23 cout<<"xPos:"<<xPos<<",yPos:"<<yPos<<endl; 24 } 25 }; <—————————————文件名example809.cpp———————————————> 26 #include"point.h" 27 int main() 28 { 29 point pt1(3,4); 30 pt1. print(); 31 point pt2=pt1;//等价于point pt2(pt1),调用复制构造函数 32 pt2. print(); 33 point pt3; 34 pt3. print(); 35 point pt4(pt3);//等价于point pt4=pt3,调用复制构造函数 36 pt4. print(); 37 return 0; 38 }

    输出结果如下所示。


    调用构造函数 xPos:3,yPos:4 调用复制构造函数 xPos:3,yPos:4 调用构造函数 xPos:0,yPos:0 调用复制构造函数 xPos:0,yPos:0

    【代码解析】即使去掉复制构造函数的定义,编译器也会自动添加默认构造函数,该代码仍能正确运行,但为了更清晰地展现复制构造函数的调用机制,在代码第15行,point类中显式定义了复制构造函数,为了区分带默认参数的构造函数和复制构造函数,在其中分别添加了输出语句“cout<<"调用构造函数"<<endl;”和“cout<<"调用复制构造函数"<<endl;”,从输出结果来看,“point pt1(3,4);”和“point pt3;”都是由构造函数完成初始化的,而“point pt2=pt1;”和“point pt4(pt3);”并没有执行构造函数,而是执行了复制构造函数,用对象pt1和pt3分别为pt2和pt4初始化。

    提示“point pt2=pt1;”等价于“point pt2(pt1);”。