第五篇:明确拒绝不想编译器自动生成的拷贝构造函数和赋值运算符重载函数
前言
如果你不想要编译器帮你自动生成的拷贝机制 (参考前文),那么你应当明确的拒绝。
如何拒绝?这便是本文要解决的主要问题。
问题描述
当你定义了一个类,而这个类中各对象之间也是封装的 - 禁止同类对象之间的相互赋值以及复制,那么你需要屏蔽掉编译器帮你生成的拷贝构造函数以及赋值运算符。
在许多代码中,会看到通过将拷贝构造函数和赋值运算符重载函数声明为私有且不予实现来实现这个功能。然而,这不是最科学的做法。
因为这没有做到真正的屏蔽:你在自己的成员函数中,或者友元函数中仍然可以调用这两个私有函数,编译器将不会报错。
也许你会狡辩,这种做法的私有拷贝构造函数以及赋值运算符重载函数都没有实现,编译器会报错。但,报错的不是编译器,是链接器。优质的代码应当将错误尽可能的移至编译期。
科学的做法
首先专门为阻止拷贝动作设计一个类,如下:
1 class Uncopyable { 2 protected: 3 Uncopyable() {} // 允许派生类对象构造,析构。 4 ~Uncopyable() {} 5 private: 6 Uncopyable(const Uncopyable &); // 但阻止拷贝 7 Uncopyable& operator=(const Uncopyable &); 8 };
如果你需要屏蔽掉某个类的拷贝机制,需要做的只是私有继承该类:
1 1 class A : private Uncopyable { 2 2 //...... 3 3 };
类 A 的拷贝函数被顺利屏蔽掉了。当 A 类对象发生拷贝或赋值,必然会先去执行其父类 Uncopyable 类的拷贝构造函数或重载赋值运算符函数。但这两个函数在 Uncopyable 中已经被声明为私有了,因此编译器会不通过。
小结
这种做法的科学依据在于,目标类的成员函数或者友元函数也都无法调用被屏蔽的拷贝构造函数和赋值运算符重载函数。
如果调用发生,报错的也是编译器,而非链接器。