默认生成的函数和屏蔽它们的方法
——《Effective C++》读书笔记4
如果你只是声明一个空类,不做任何事情的话,编译器会自动为你生成:
一个默认构造函数
一个拷贝默认构造函数
一个默认拷贝赋值操作符
一个默认析构函数
这些函数只有在第一次被调用时,才会别编译器创建。所有这些函数都是inline和public的。默认的析构函数是非虚函数(除非基类有自己声明的虚析构函数)。而拷贝默认构造函数和默认拷贝赋值操作符知识是单纯将来源对象的每一个非静态成员拷贝到对象目标中(bitwise copy)。其中的默认拷贝赋值操作符只有在生成的代码合法并且有机会证明它有意义存在时才会生成。这就说明,如果你打算在一个“内含引用成员”或者“内含const成员”的类内支持赋值操作,就必须定义自己的默认拷贝赋值操作符。因为C++本身不允许引用改指不同的对象,也不允许更改const成员。
最后一种情况,当基类将自己的默认拷贝赋值操作符声明为private时,子类就不会产生自己的的默认拷贝赋值操作符。因为假如产生了这样的默认拷贝赋值操作符,它会试着去调用基类的默认拷贝赋值操作符去处理基类的部分,不幸的是,它没有权利。
你可以将拷贝构造函数或默认拷贝赋值操作符声明为private。这样明确声明一个成员函数,就阻止了编译器暗自创建的默认版本,而这些函数为private,使得可以成功阻止人们调用它。
上面的做法有一个隐患,因为类自身的member和friend还是可以调用这些private函数。有一个很刁钻的方法,“将成员函数声明为private而且故意不实现它们”,这样既阻止了默认函数的生成,而且如果你试着调用这些函数,就会得到一个链接错误。只声明,不定义,链接器报错。甚至在声明的时候,你连参数也不用写。
而试着将上述的链接器错误提前到编译器也是可以的。我们专门设计一个类Unconpyable。
--------------------------------------------------------------------
class Uncopybale {
protected:
Uncopyable() {}
~Uncopyable() {}
private:
Ucopyable(const Uncopyable&)
Uncopyable& operator=(const Uncopyable&)
};
--------------------------------------------------------------------
为了阻止对象被拷贝,我们唯一需要做的就是继承Uncopyable。这些函数的默认生成版本会尝试调用其基类的对应版本,那些调用会被编译器拒绝,因为它基类的拷贝函数是private。
Boost提供的noncopyable类也有类似的功能。
忠告:
(1)为了驳回编译器自动提供的技能,可将相应的成员函数声明为private并且不予实现。
(2)使用像Uncopyable这样的基类也是一种做法。