[C++ Primer] 复制控制

复制构造函数:当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式使用复制构造函数 A a = A();当将该类型的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数(显式使用和隐式使用的区别?)

析构函数:当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。

复制构造函数,赋值操作符和析构函数总称为复制控制。编译器自动实现这些操作,但类也可以定义自己的版本。

1.只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数称为复制构造函数。C++支持直接初始化(使用“()”)和复制初始化(使用“=”)两种形式。直接初始化调用与实参匹配的构造函数,复制初始化则调用复制构造函数(注意:

ClassTest ct3 = ct1;复制初始化,
ClassTest ct4(ct1);直接初始化
注:都是调用复制构造函数,但是调用复制函数的原因却有所不同。因为直接初始化是根据参数来调用构造函数的,如ClassTest ct4(ct1),它是根据括号中的参数(一个本类的对象),来直接确定为调用复制构造函数ClassTest(const ClassTest& ct),这跟函数重载时,会根据函数调用时的参数来调用相应的函数是一个道理;而对于ct3则不同,它的调用并不是像ct4时那样,是根据参数来确定要调用复制构造函数的,它只是因为初始化必然要调用复制构造函数而已。 ) 。通常直接初始化和复制初始化仅在低级别优化上存在差异,然而对不支持复制的类型或者使用非explicit构造函数的时候,还是有本质的区别:

ifstream file1("filename");

ifstream file2  = "filename";

Sales_item item = string("9-999-99999-9");

file1的初始化没问题,file2使用复制初始化,但是由于不能复制IO类型的对象,所以不能对那些类型的对象使用复制初始化。

如果Sales_item参数为string类型的构造函数且其类型声明为非explicit(此时string("9-999-99999-9")将转换为Sales_item类型)时item的初始化是对的,否则初始化失败。

2.初始化容器元素:vector svec(5);编译器首先使用string的默认构造函数创建一个临时值初始化svec,然后使用复制构造函数将临时值复制到svec的每个元素。

3.复制构造函数和构造函数一样,如果显示的定义,编译器会合成默认的复制构造函数,对于只包含类类型成员或内置成员的类,合成的默认复制构造函数就可以了。但是有些类必须对复制对象时发生的事情加以控制,这样的类经验有一个数据成员是指针或者有成员表示在构造函数中分配的其他资源(想象一下两个buffer指针指向同一块内存)。

4.禁止复制:有些类比如io类不允许复制,为了防止复制,类必须声明其复制构造函数为private(不定义复制构造函数的话,编译会合成默认的复制构造函数)---如果复制构造函数是private,将不允许用户代码复制该类类型的对象。然后类的友元和成员仍然可以进行复制(友元和成员可以访问类的private成员),如果想要连友元和成员中的复制也禁止,就可以声明一个private复制构造函数但不对其定义。用户代码中的复制尝试在编译时标记错误,而成员函数和友元中的复制尝试将在链接时导致错误。

5.三法则:如果类需要析构函数,则它也需要赋值操作符和复制构造函数,析构函数与复制构造函数或赋值操作符之间的一个重要区别是:即使编写了自己的析构函数,合成析构函数仍然运行。

6.管理指针成员:包含指针的类要特别注意复制控制,原因是复制指针时只复制指针中的地址,而不会复制指针指向的对象。当两个指针指向同一对象,可能使用任一指针改变基础对象,很可能一个指针删除了以对象时,另一指针的用户还认为基础对象仍然存在并访问,这会造成极大的风险,因此引入智能指针。

7.进一步理解直接初始化和复制初始化http://blog.csdn.net/ljianhui/article/details/9245661C++的一大误区——深入解释直接初始化与复制初始化的区别 

你可能感兴趣的:(C/C++)