类进行拷贝初始化时会调用拷贝构造函数,拷贝初始化发生在以下几种情况中:
[1] 有“=”的地方会发生拷贝;
[2] 将一个对象作为参数传递给一个非引用的对象时;
[3] 从一个返回类型为引用的类型的函数返回一个对象;
[4] 用花括号初始化一个数组中的元素;
拷贝构造函数的形参必须为引用类型,我认为应该有两点原因:
1. 在类的类部定义该类的对象,只能定义为引用类型或指针类型,因为其属于不完全类型;
2. 如果不定义为引用就会陷入无限的循环——调用拷贝构函数,必须拷贝它的实参,而拷贝它的实参就要调用拷贝构造函数
根据下面的实例我们来分析一下拷贝构造函数的调用,大家可以先自己思考一下程序的输出是什么?
1 #include2 #include 3 using namespace std; 4 class Point 5 { 6 public: 7 Point(int xx = 0, int yy = 0) 8 { 9 x = xx;10 y = yy;11 cout << "calling the constructor of point" << endl;12 }13 14 Point(const Point & p)15 {16 x = p.x;17 y = p.y;18 cout << "calling the copy constructor of point" << endl;19 }20 21 int getx() const22 {23 return x;24 }25 26 int gety() const27 {28 return y;29 }30 private:31 int x, y;32 };33 34 class Line35 {36 public:37 Line(Point pa, Point pb)38 :p1(pa), p2(pb)39 {40 cout << "calling the constructor of Line" << endl;41 double x = static_cast (p1.getx() - p2.getx());42 double y = static_cast (p1.gety() - p2.gety());43 len = sqrt(x*x +y*y);44 }45 46 Line(const Line & L)47 :p1(L.p1), p2(L.p2)48 {49 len = L.len;50 cout << "calling the copy constructor of Line" << endl;51 }52 53 double getLen() const54 {55 return len;56 }57 private:58 Point p1, p2;59 double len;60 };61 62 63 int main()64 {65 Point myp1(1, 1), myp2(4, 5);66 Line L1(myp1, myp2);67 Line L2(L1);68 cout << "the lenth of L1 is" << L1.getLen() << endl;69 cout << "the lenth of L2 is" << L2.getLen() << endl;70 return 0;71 }
第65行程序,定义了两个Point对象,采用直接初始化,因此会调用两次Point的构造函数;
第66行程序,定义了一个Line对象,采用直接初始化,因此会调用Line的构造函数,但是在调用Line的构造函数之前调用了4次Point的拷贝构造函数,为什么会这样呢?
第一次:myp1作为实参传递给Line的构造函数发生一次拷贝;
第二次:myp2作为实参传递给line的构造函数发生一次拷贝;
第三次:myp1拷贝初始化Line的p1数据成员时发生一次拷贝;
第四次:myp2拷贝初始化Line的p2数据成员时发生一次拷贝;
第67行程序,定义了一个Line的对象,采用拷贝初始化,因此需要调用Line的拷贝构造函数,但是在调用LIne的拷贝构造函数之前,调用了两次Point的拷贝构造函数,这是因为:
46 Line(const Line & L)47 :p1(L.p1), p2(L.p2)
用L.p1初始化p1是发生一次拷贝,同理p2也发生了相同的拷贝,因此调用了两次Point的拷贝构造函数。