Effective C++——条款6(第2章)

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

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

    在某些情况下, 希望保持对象的唯一性,不想让对象有其他副本.如下:
class HomeForSale { ... };
HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1);        // 企图拷贝h1,不应该通过编译
h1 = h2;                   // 企图拷贝h2,不应该通过编译
    阻止这一类代码的编译并不是很直观.通常如果不希望 class 支持某一个特定机能,只要不声明对应的函数就可以了.但 这个策略对copy构造函数和copy assignment操作符却起不到作用.因为条款5已经指出,如果不声明它们,而某些人尝试调用它们,编译器会声明它们.
    这就进入了一个困境. 如果不声明copy构造函数和copy assignment操作符,编译器可能产出一份.于是 class 就支持copying.如果声明它们,class 还是支持copying,而目标却是要阻止copying(保持对象的唯一性).
    答案的关键是,所有编译器产出的函数都是 public.为阻止这些函数被创建出来,需要自行声明它们,但这里并没有什么需求使必须将它们声明为 public.因此可以将copy构造函数和copy assignment操作符声明为 private. 借由明确地声明一个成员函数,可以阻止编译器暗自创建其专属版本;而令这些函数为 private,得以成功阻止其他人调用它.
    一般而言这个做法并不绝对安全,因为member函数和 friend 函数还是可以调用 private 函数.除非不定义它们,那么如果某些人不慎调用任何一个,就会获得一个连接错误. "将成员函数声明为private并且故意不实现它们"这一伎俩广为人接受,因而被用在C++iostream程序库中阻止copying行为.如果看看标准程序库实现码中的ios_base,base_ios和sentry.会发现无论哪一个,其copy构造函数和copy assignment操作符都被声明为 private 且没有定义.
    将这个伎俩施行于HomeForSale也很简单:
class HomeForSale {
public:
    ...
private:
    HomeForSale(const HomeForSale &);            // 只有声明
    HomeForSale& operator=(const HomeForSale&);
};
    有了上述定义,当客户企图拷贝HomeForSale对象,编译器会阻止它.如果不慎在member函数或 friend 函数内那么做,连接器则会阻止.
    将连接期错误移动至编译器是可能的(而且是好事,毕竟越早侦测出错误越好), 只要将copy构造函数和copy assignment操作符声明为 private 就可办到,但不是在HomeForSale自身,而是 在一个专门为了阻止copying动作而设计的base class 内.这个base class 非常简单:
class Uncopyable {
protected:                                // 允许derived对象构造和析构
    Uncopyable() {}
    ~Uncopyable() {}
private:
    Uncopyable(const Uncopyable&);        // 阻止copying
    Uncopyable* operator=(const Uncopyable&);
};
    为了阻止HomeForSale对象被拷贝,唯一需要做的就是继承Uncopyable:
class HomeForSale : private Uncopyable {    // class不再需要声明copy构造函数
};
    这是行得通的,因为只要任何人——甚至是member函数或 friend 函数——尝试拷贝HomeForSale对象,编译器便试着生成一个copy构造函数和一个copy assignment操作符,而正如条款12所述,这些 函数的"编译器生成版"会尝试调用其base class 的对应兄弟,那么调用会被编译器拒绝,因为其base class 的拷贝函数是 private.
    Uncopyable class 的实现和运用颇为微妙,包括不一定得以 public 继承它,以及Uncopyable的析构函数不一定得是 virtual 等等.Uncopyable不含数据,因此符合条款39所述的empty base class optimization资格.但由于它总是扮演base class,因此这项技术可能导致多重继承(因为往往还需要继承其他 class),而多重继承有时会阻止empty base class optimization.通常可以忽略这些微妙点.
     注意:
    为驳回编译器自动(暗自)提供的机能,可将相应的成员函数声明为 private 并且不予实现.使用像Uncopyable这样的base class 也是一种做法.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值