Effective C++ 08 复制构造函数 木灵的炼金工作室

这是Effective C++的学习记录。

条款12:关于复制构造函数

保证实例的每一部分都被复制构造

前面提过,如果不希望使用C++的缺省复制构造函数,就需要使用手写的复制构造函数来重载它。比如我希望在每一次调用复制构造函数时输出字符串:

class example{
private:
    int val;
public:
    example(const example& x) 
        : val(x.val) { 
        cout << "Copy construct"; 
    }
};

这种情况看起来没什么问题,而且确实也没什么问题,但是,如果情况变成这样呢?

class example : public base{
private:
    int val;
public:
    example(const example& x)
        : val(x.val) {
        cout << "Copy construct";
    }
};

请仔细观察上述的程序,找出其中的问题。
很容易发现,example类是一个派生类,但是在它的复制构造函数中貌似未对其基类base做出显式构造,因此编译器会调用基类的缺省构造函数,这就会引发新实例的基类成员与被复制实例的基类成员不同,这是一个致命的问题,会导致我们的复制构造函数发生功能上的问题。这个问题需要引起十足的注意。对此,使用委托构造函数,以下的代码可以解决这个问题:

class example : public base{
private:
    int val;
public:
    example(const example& x) 
        : val(x.val), base(x) { 
            cout << "Copy construct"; 
        }
};

委托构造函数通过派生类x构造了一个基类,作为新实例的基础实例。
这个例子提示我们,在编写复制构造函数时,我们不仅需要考虑派生类的所有成员变量,我们也需要考虑实例的基类。

不使用重载的赋值运算符完成复制构造

使用重载赋值运算符完成复制构造在逻辑上是有错误的。
调用构造函数时,我们的实例还不存在,因此作为实例成员的所谓赋值运算符也是不存在的,而赋值运算符在规定上不拥有构造全部成员的功能。换句话说,赋值运算符只对已构造的实例生效,所以说调用它进行复制是完全错误的。当然有的时候这么写也能过编译,没准儿也会呈现正常的功能,但是请记住,这种做法是不合适的,别试!

同样的,使用复制构造函数来实现赋值运算也是不合适的。试图构造一个已经存在的实例也是不合适的。

但是,很多情况下,赋值重载和复制构造函数有着很大的公共代码,那么基于我们工程师的精益求精原则,我们需要复用它,但是如何复用呢?
一种直观的做法是将公有部分提取出来,写成一个私有成员函数。


Copyright AmachiInori 2017-2021. All Right Reserved.
Powered By Jekyll.
amachi.com.cn