C++ allows the programmer to define how objects are to be copied, moved, assigned and destroyed. Together these are known as copy control.
拷贝控制的基础
一、复制初始化
复制初始化 de 使用
Ref: C++的一大误区——深入解释直接初始化与复制初始化的区别
#include <iostream> #include <cstring> using namespace std; class ClassTest { public: ClassTest() { c[0] = '\0'; cout<<"ClassTest()"<<endl; }
ClassTest& operator=(const ClassTest &ct) { strcpy(c, ct.c); cout<<"ClassTest& operator=(const ClassTest &ct)"<<endl; return *this; }
ClassTest(const char *pc) { strcpy(c, pc); cout<<"ClassTest (const char *pc)"<<endl; }
ClassTest(const ClassTest& ct) { strcpy(c, ct.c); cout<<"ClassTest(const ClassTest& ct)"<<endl; }
private: char c[256]; };
1、ClassTest ct1("ab");
这条语句属于直接初始化,它不需要调用复制构造函数,直接调用构造函数ClassTest(const char *pc),所以当复制构造函数变为私有时,它还是能直接执行的。
2、ClassTest ct2 = "ab";
这条语句为复制初始化,它首先调用构造函数ClassTest(const char *pc)函数创建一个临时对象,然后调用复制构造函数,把这个临时对象作为参数,构造对象ct2;所以当复制构造函数变为私有时,该语句不能编译通过。
3、ClassTest ct3 = ct1;
这条语句为复制初始化,因为ct1本来已经存在,所以不需要调用相关的构造函数,而直接调用复制构造函数,把它的值复制给对象ct3;所以当复制构造函数变为私有时,该语句不能编译通过。
4、ClassTest ct4(ct1);
这条语句为复制初始化,因为ct1本来已经存在,直接调用复制构造函数,生成对象ct1的副本对象ct4。所以当复制构造函数变为私有时,该语句不能编译通过。
注:第4个对象ct4与第3个对象ct3的创建所调用的函数是一样的,但是本人却认为,调用复制函数的原因却有所不同。因为直接初始化是根据参数来调用构造函数的,如ClassTest ct4(ct1),它是根据括号中的参数(一个本类的对象),来直接确定为调用复制构造函数ClassTest(const ClassTest& ct),这跟函数重载时,会根据函数调用时的参数来调用相应的函数是一个道理;而对于ct3则不同,它的调用并不是像ct4时那样,根据参数来确定要调用复制构造函数的,它只是因为初始化必然要调用复制构造函数而已。它理应要创建一个临时对象,但只是这个对象却已经存在,所以就省去了这一步,然后直接调用复制构造函数,因为复制初始化必然要调用复制构造函数,所以ct3的创建仍是复制初始化。
5、ClassTest ct5 = ClassTest();
这条语句为复制初始化,首先调用默认构造函数产生一个临时对象,然后调用复制构造函数,把这个临时对象作为参数,构造对象ct5。所以当复制构造函数变为私有时,该语句不能编译通过。
编译器暗中优化
编译会帮你做很多你看不到,你也不知道的优化,
"你看到的结果,正是编译器做了优化后的代码的运行结果,并不是你的代码的真正运行结果。"
二、访问权限
复制构造函数是可以由编译默认合成的,而且是公有的(public),编译器就是根据这个特性来对代码进行优化的。
如果你自己定义这个复制构造函数,编译则不会自动生成,虽然编译不会自动生成,但是如果你自己定义的复制构造函数仍是公有的话,编译还是会为你做同样的优化。
当它是私有成员时,编译器就会有很不同的举动,因为你明确地告诉了编译器,你明确地拒绝了对象之间的复制操作,所以它也就不会帮你做之前所做的优化,你的代码的本来面目就出来了。
public 的 复制构造函数
#include <iostream> #include <algorithm> #include <vector> #include <string> using namespace std; class CExample { private: int a; public: CExample(int b) { a=b; printf("constructor is called\n"); } CExample(const CExample & c) { a=c.a; printf("copy constructor is called\n"); } ~CExample() { cout<<"destructor is called\n"; } void Show() { cout<<a<<endl; } }; int main(void) { CExample A(100); CExample B=A; CExample C=CExample(A); B.Show(); return 0; }