蓝图
这条其实基本上就是针对copy构造函数和copy assignment操作符这两个函数的,为什么这么说呢,其他的函数,不想用的话,不要声明不要定义就完了,但是copy构造函数和copy assignment操作符不声明不定义的话编译器会自动整一套public的出来,所以这让人比较为难,作者给出了两个方案:
- 声明为private,但是不予以定义;
- 使用Uncopyable base class;
声明为private,不予以定义
这是一个一步步的逻辑
- 不想让编译器提供copy构造函数和copy assignment操作符,那么我们必须予以声明;
- 为了不让其他人调用copy构造函数和copy assignment操作符,将其声明为private;
- 为了防止member函数和friend函数调用copy构造函数和copy assignment操作符,不予以定义使得工程在链接阶段报错;
class TstCls {
public:
...
private:
TstCls(const TstCls&); //只有声明,不要定义
TstCls& operator=(const TstCls&);
}
显然这里又应用到了【条款5】笔记中说到的只声明不定义的情况。总的来说,感觉这是一个不怎么地道的办法,总有一种野路子的味道。另外,把错误提示从链接阶段提前到编译阶段总是好的,因此,作者又提出了Uncopyable bass class方法。
Uncopyable base class
即然是担心private声明的函数被其他member函数或friend函数调用,那么干脆就定义一个没有其他member函数,也没有friend函数的base class,就像这样
class Uncopyable {
protected:
Uncopyable(){} //允许derived对象构造和析构
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&); //但是阻止copying
Uncopyable& operator=(const Uncopyable&);
};
然后假如我们的TstCls不想要copy构造函数和copy assignment操作符,直接继承上面这个Uncopyable类就可以了。
作者给出的示例是这样的:
class HomeForSale: private Uncopyable {
... //class不再声明copy构造函数,也不再声明copy assign操作符,当然也不要定义
};
这样编译器在尝试生成这两个copy函数时会去试图调用Uncopyable的对应的copy函数,但是Uncopyable的copy函数都是private的不能被derived class调用,因此编译出错。
其他
作者两句话值得仔细品味:
1.Uncopyable class的运用颇为巧妙,不一定得以public继承它:那到底该用public继承还是private继承,有什么影响区别?
2.Uncopyable的析构函数不一定得是virtual:那到底该不该是virtual,有什么影响区别?
从【条款7】可以看到,只有准备用于base class的类的析构函数才得是virtual的,因为virtual函数存在的意义就是多态,都不打算做base class,多态也就无从谈起,此时莫说析构函数,任何成员函数都不应该是virtual的,避免无端增大class的size。Uncopyable类虽然也是被继承的,但是其并不会用于多态的目的,因此没有必要使得析构函数是virtual的;