0.概述:
为了阻止编译器自动生成的函数,通常有以下2种解决方案:
- 将相应的成员函数声明为private并且不予实现。
- 使用如Uncopyable这样的基类
1.解决方案①
通常如果不希望类支持某项机能,只要不声明相应函数即可。但类的拷贝构造函数和拷贝赋值函数是个例外,如果你不声明,但有人试图调用它们,编译器会自动为你声明(而且编译器产出的函数都是public的)。
解决方案思路如下:
- 明确声明一个成员函数,可以阻止编译器自动创建
- 将其声明为private,可以阻止别人调用。
但上述解决方案依然存在漏洞,因为类的私有函数可以被类的成员函数和友元函数调用,因此上述解决方案的第二条可以修改为:
- 声明为private但不给予定义。
这种解决方案在C++标准库中比比皆是,下面举个例子:
class HomeForSale {
public:
...
private:
...
HomeForSale(const HomeForSale&); // declarations only
HomeForSale& operator=(const HomeForSale&);
};
在这个例子中,根本就没写这两个函数参数的名称,反正这个函数不会被实现,所以根本没必要写名称。
这样之后,
- 当你试图拷贝HomeForSale对象,编译器会发出警告(私有函数,无法调用)。
- 当你在成员函数或友元函数中这么做,连接器会发出警告(函数为空。连接错误)。
2.解决方案②
为了及早检测出报错,可以将连接期的报错迁移到编译期。这可以通过在一个专门为阻止拷贝相关动作而设计的基类中将拷贝构造和拷贝赋值设置为私有来实现。
该基类的实现如下:
class Uncopyable {
protected:
Uncopyable() {} // 允许构造和
~Uncopyable() {} // 析构
private:
Uncopyable(const Uncopyable&); // 但阻止拷贝
Uncopyable& operator=(const Uncopyable&);
};
为了阻止HomeForSale对象被拷贝,只需继承Uncopyable类:
class HomeForSale::private Uncopyable
{...}; //类中将不再声明拷贝构造及赋值
这样之后,只要任何人尝试拷贝HomeForsale对象,哪怕是member函数或friend函数,编译器便试着生成一个copy构造函数和一个copy assignment操作符,这些函数的“编译器生成版”会尝试调用其 base class的对应兄弟,那些调用会被编译器拒绝,因为其base class 的拷贝函数是private。
注:因为Uncopyable总是扮演基类,有时会导致多重继承。