C++中复制构造函数和赋值操作符
先看一个例子:
定义了一个类:
再定义一个类Test:
- 当我们仅仅定义一个Test类对象test1时:
输出结果:
- 此时如果用test1初始化一个Test类对象test2:
输出结果为:
原因在于,给test2初始化的时候调用了Test类中的复制构造函数,而这个复制构造函数中:
又有对成员的初始化列表,即对成员TestChild tc进行初始化,这里由于是对未初始化的对象进行初始化,所以使用了TestChild的复制构造函数。而tc=test.tc是对已经初始化的对象进行赋值,所以使用的是赋值操作符。
- 如果我们把Test类的复制构造函数改为:
此时再执行Test test2=test1,输出结果为:
因为,test2被test1初始化的时候调用了Test类的复制构造函数,而由于此时Test的复制构造函数没有初始化列表,Test类成员就使用的是TestChild tc的默认构造函数。而后再tc=test.tc中,由于tc已经被初始化,所以使用了赋值操作符。
- 如果再将复制构造函数改为:
此时再执行Test test2=test1,输出结果为:
因为,这里在Test的复制构造函数的初始化列表中对tc进行了初始化,所以就不会再用tc的默认构造函数初始化了。
- 如果我们这里再对一个test3这样初始化:
重复前面三步,结果是完全一样的。虽然Test test2=test1和Test test3(test2)表面形式上来看不同,但是他们实际上做的事是相同的,这说明我们不能从表面上来判断它是调用的复制构造函数还是赋值操作符,而需要看具体执行的是什么操纵。如果执行的是自己初始化,那么使用的是默认构造函数;如果用别的对象对自己进行初始化,那么使用的是复制构造函数;如果自身已经初始化过,而用别的对象对自己进行赋值,那么使用的就是赋值操作符。
- 如果我们此时再多写一句:test3=test1,则会输出结果:
原因在于,test3是已经初始化过的对象,再对test3赋值,就调用了Test类的赋值操作符:
而Test类的赋值操作符中,又有对tc的赋值,因为test1也初始化过了,这里再对test1赋值就调用了TestChild类的赋值操作符。
全部代码如下:
class TestChild { public: TestChild() { x = 0; y = 0; cout << "TestChild: Default Constructor!" << endl; } ~TestChild(){} TestChild(const TestChild& tc) { x = tc.x; y = tc.y; cout << "TestChild: Copy Constructor!" << endl; } const TestChild& operator=(const TestChild& right) { x = right.x; y = right.y; cout << "TestChild:Assignment operator!" << endl; return *this; } int x, y; }; class Test { public: Test(){ printf("Test: Default Constructor!\n"); } explicit Test(const TestChild& tcc) { tc = tcc; } ~Test(){} /*Test(const Test& test) :tc(test.tc)//tc(test.tc),这里是对tc进行初始化,所以调动的是Copy Contrustor { tc = test.tc;//这里是赋值所以调用的是assignment operator printf("Test: Copy Constructor!\n"); }*/ /*Test(const Test& test) { tc = test.tc;//先Construct tc,在对tc assignment operator printf("Test: Copy Constructor!\n"); }*/ /*Test(const Test& test) :tc(test.tc)//这里直接用复制构造函数初始化,而忽略了下边TestChild tc { printf("Test: Copy Constructor!\n"); }*/ const Test & operator=(const Test& right) { tc = right.tc;//这里又有对数据成员tc的赋值,已经初始化过的tc再次赋值,此处也调用了 //TestChild的赋值操作符 printf("Test:Assignment operator!\n"); return *this; } TestChild tc; }; int main() { Test test1;//调用自身的默认构造函数;由于有成员TestChild,所以也会调用TestChild的默认构造函数 cout << "---------------------------------------------" << endl; Test test2 = test1;//用test1构造一个不存在的test2,所以这里是调用的test2的复制构造函数; cout << "---------------------------------------------" << endl; Test test3(test2); cout << "---------------------------------------------" << endl; test3 = test1; system("pause"); return 0; }
做一个总结,参考:http://bbs.csdn.net/topics/210020066
复制构造函数
拷贝构造函数,经常被称作X(X&),是一种特殊的构造函数,他由编译器调用来完成一些基于同一类的其他对象的构件及初始化。它的唯一的一个参数 (对象的引用)是不可变的(因为是const型的)。这个函数经常用在函数调用期间于用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数 和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用。
在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。
1). 一个对象以值传递的方式传入函数体
2). 一个对象以值传递的方式从函数返回 (对象传入函数和从函数返回一个对象,都是利用的对象的一个副本)
3). 一个对象需要通过另外一个对象进行初始化
以上的情况需要拷贝构造函数的调用。(这三种情况其实都是执行的初始化)
“一个用于构造对象(构造过程中的拷贝),一个用于拷贝对象(构造完成以后的拷贝)”
“用一个已存在的对象去构造一个不存在的对象(构造之前不存在),就是拷贝构造;用一个已存在的对象去覆盖另一个已存在的对象,就是赋值运算. ”