条款06:若不想使用编译器自动生成的函数,就该明确拒绝

条款06:若不想使用编译器自动生成的函数,就该明确拒绝

Explicitly disallow the use of compiler-generated functions you do not want.

拒绝拷贝操作

首先,从一个例子入手:
对于一个房产中介,它所使用的中介软件需要一个class来描述待售房屋

class HomeForSale { ... };

对于这样的房产,HomeForSale对象产生一个副本没有任何道理,因此,任何想对该对象进行拷贝的动作都应该失败:

HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); //试图拷贝h1-应该被拒绝
h1 = h2;            //试图拷贝h2-应该被拒绝

一般来说,如果我们不想使用某种函数,只要不去声明它就好。但是对于copy构造函数和copy assignment操作符却不行:因为如果我们不去声明它们,而又有其他人对其进行尝试调用,则编译器会自动声明它们!

对于这样的问题的关键点在于,所有的编译器产出的函数都是public的。因此,我们可以人为地将copy构造函数和copy assignment操作符声明为private
此时,这样的操作阻止了编译器暗自创建默认的版本,而且令这些函数为private,可以阻止其他人的调用。

但是,这种办法并不是最优解。因为member函数friend函数还是可以去调用这些private函数。因此,一个经常使用的讨巧办法则是:

  • 将成员函数声明为private而且故意不去实现它们

因此,对于上面的例子:

class HomeForSale {
public:
    ...
private:
    ...
    HomeForSale(const HomeForSale&);    //只有声明而没有定义
    HomeForSale& operator=(const HomeForSale&);

当我们有了上述的class定义,当有人企图拷贝HomeForSale对象时,编译器会阻止(因为private)。而如果有member函数或friend函数尝试这样做,也会出现连接错误(linkage error)

Uncopyable class

上面这种解决办法是可行的,将连接错误迁移至编译期,更高的侦测出错误,对程序是有好处的。
但是不应该在HomeForSale class内实现,而是应该定义在专门为了阻止copying动作而设计的base class内。

class Uncopyable {
protected:
    Uncopyable() {}  //允许derived对象构造和析构
    ~Uncopyable() {}
private:
    Uncopyable(const Uncopyable&);   //但是阻止copying
    Uncopyable& operator=(const Uncopyable&);
};

为了阻止HomeForSale对象被拷贝,只需要继承这个Uncopyable类即可:

class HomeForSale : private Uncopyable {
    ...    //此时,HomeForSale class内不再声明copy构造函数和copy assignment操作符
 };

为了驳回编译器自动(暗自)提供的机能,可以将相应的成员函数声明为private并且不予实现。使用像Uncopyable这样的base class也是一种做法。

猜你喜欢

转载自blog.csdn.net/lym940928/article/details/80955531