通常如果你不希望class支持某一特定机能,只要不声明对应函数就是了。但这个策略对copy构造函数和copy assignment操作符却不起作用。如果你自己没有声明,编译器就会为你的class声明(编译器版本的)一个copy构造函数、一个copy assignment操作符和一个析构函数。(此外如果你没有声明任何构造函数,编译器也会为你声明一个default构造函数。所有这些函数都是public且inline.)于是你的class被强迫支持copying,然而这里的目标却是要阻止copying。
答案的关键是,所有编译器产生的函数都是public。为阻止copy函数被创建出来,你可以将copy构造函数或copy assignment操作符声明为private。藉由明确声明一个成员函数,你阻止了编译器暗自创建其专属版本;而令这些函数为private,使你得以成功阻止人们调用它。一般而言这个做法并不绝对安全,因为member函数和friend函数还是可以调用你的private函数。
除非你只声明,却不定义它们,那么如果任何不慎调用都会获得一个链接错误(linkage error)。如此一来,当客户企图拷贝你的class对象,编译器会阻挠他。如果你不慎在member函数或friend函数之内那么做,轮到连接器发出抱怨。
有没有可能将链接错误移至编译期?(毕竟愈早侦测出错误愈好)。答案是可行的。
注:千万不要画蛇添足在Derived class中再次private声明copy构造函数和copy assignment操作符,否则会阻挡编译器生成版的尝试。切记!
答案的关键是,所有编译器产生的函数都是public。为阻止copy函数被创建出来,你可以将copy构造函数或copy assignment操作符声明为private。藉由明确声明一个成员函数,你阻止了编译器暗自创建其专属版本;而令这些函数为private,使你得以成功阻止人们调用它。一般而言这个做法并不绝对安全,因为member函数和friend函数还是可以调用你的private函数。
除非你只声明,却不定义它们,那么如果任何不慎调用都会获得一个链接错误(linkage error)。如此一来,当客户企图拷贝你的class对象,编译器会阻挠他。如果你不慎在member函数或friend函数之内那么做,轮到连接器发出抱怨。
有没有可能将链接错误移至编译期?(毕竟愈早侦测出错误愈好)。答案是可行的。
方法就是专门设计一个阻止copying的base class,并将其copy构造函数和copy assignment操作符声明为private。
class Uncopyable
{
public:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable& other);
Uncopyable& operator=(const Uncopyable& other);
};
为求阻止class对象被拷贝,我们唯一需要做的就是继承Uncopyable:class Derived : public Uncopyable
{
public:
//...
private:
//Derived& operator=(const Derived& other);
//Derived(const Derived& other);
void func()
{
//Error 1 error C2248: 'Uncopyable::Uncopyable' : cannot access private member declared in class 'Uncopyable'
Derived one = *this;
}
};
这样,任何人--甚至是member函数或friend函数--尝试拷贝Derived对象,编译器便试着生成一个copy构造函数和一个copy assignment操作符。这些函数的“编译器生成版”会尝试调用其base class的对应兄弟,那些调用会被编译器拒绝,因为其base class的拷贝函数是private。注:千万不要画蛇添足在Derived class中再次private声明copy构造函数和copy assignment操作符,否则会阻挡编译器生成版的尝试。切记!
引自《Effective C++》