分享
 
 
 

翻译:Effective C++, 3rd Edition, Item 6: 如果你不想使用编译器为你产生的函数,就明确拒绝

王朝c/c++·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

Item 6: 如果你不想使用编译器为你产生的函数,就明确拒绝

不动产代理商出售房屋,服务于这样的代理商的软件系统自然要有一个类来表示被出售的房屋:

class HomeForSale { ... };

每一个不动产代理商都会很快指出,每一件财产都是独特的——没有两件是完全一样的。在这种情况下,为 HomeForSale 对象做一个拷贝的想法就令人不解了。你怎么能拷贝一个独一无二的东西呢?最好让这种类似企图拷贝 HomeForSale 对象的行为不能通过编译:

HomeForSale h1;

HomeForSale h2;

HomeForSale h3(h1); // attempt to copy h1 - should

// not compile!

h1 = h2; // attempt to copy h2 - should

// not compile!

唉,防止这种编译的方法并非那么简单易懂。通常,如果你不希望一个 class 支持某种功能,你可以简单地不声明赋予它这种功能的函数。这个策略对于拷贝赋值运算符不起作用,因为,就象 Item 5 中指出的,如果你不声明它们,而有人又想调用它们,编译器就会隐式地声明它们。

这就限制了你。如果你不声明拷贝构造函数和拷贝赋值运算符,编译器也可以为你生成它们。你的类还是会支持拷贝。另一方面,如果你声明了这些函数,你的类依然会支持拷贝。我们在这里的目标就是防止拷贝。

解决这个问题的关键是所有的编译器生成的函数都是 public。为了防止生成这些函数,你必须自己声明它们,但是你没有理由把它们声明为 public。相反,应该将拷贝构造函数和拷贝赋值运算符声明为 private。通过显式声明一个成员函数,可以防止编译器生成它自己的版本,而且将这个函数声明为 private,可以防止别人调用它。

通常,这个方案并不十分保险,因为成员函数和友元函数还是能够调用 private 函数。换句话说,除非你不定义它们。那么,当有人不小心地调用了它们,在连接的时候会出现错误。这个窍门--定义一个 private 成员函数却故意不去实现它--确实不错,在 C++ 的 iostreams 库里,就有几个类用此方法防止拷贝。比如,看一下你用的标准库的实现中,ios_base,basic_ios 和 sentry 的定义,你就会看到拷贝构造函数和拷贝赋值运算符被声明为 private 而且没有定义的情况。

将这个窍门用到 HomeForSale 上,很简单:

class HomeForSale {

public:

...

private:

...

HomeForSale(const HomeForSale&); // declarations only

HomeForSale& operator=(const HomeForSale&);

};

你会注意到,我省略了函数参数的名字。这没有必要,只是一个普通的惯例。毕竟,函数不会被定义,极少有机会被用到,有什么必要指定参数的名字呢?

对于上面的类定义,编译器将阻止客户拷贝 HomeForSale 对象的企图,如果你不小心在成员函数或者友元函数中这样做了,连接程序会提出抗议。

将连接时错误提前到编译时间也是可行的(早发现错误毕竟比晚发现好),不要让 HomeForSale 自己去声明 private 的拷贝构造函数和拷贝赋值运算符,在一个特意设计的基类中声明。这个基类本身非常简单:

class Uncopyable {

protected: // allow construction

Uncopyable() {} // and destruction of

~Uncopyable() {} // derived objects...

private:

Uncopyable(const Uncopyable&); // ...but prevent copying

Uncopyable& operator=(const Uncopyable&);

};

为了禁止拷贝 HomeForSale 对象,我们必须让它从 Uncopyable 继承:

class HomeForSale: private Uncopyable { // class no longer

... // declares copy ctor or

}; // copy assign. operator

在这里,如果有人——甚至是成员函数或友元函数——试图拷贝一个 HomeForSale 对象,编译器将试图生成一个拷贝构造函数和一个拷贝赋值运算符。就象 Item 12 解释的,这些函数的编译器生成版会试图调用基类的对应函数,而这些调用将被拒绝,因为在基类中,拷贝操作是 private 的。

Uncopyable 的实现和使用包含一些微妙之处,比如,从 Uncopyable 继承不能是 public 的(参见 Item 32 和 39),而且 Uncopyable 的构造函数不必是 virtual 的(参见 Item 7)。因为 Uncopyable 不包含数据,所以它符合 Item 39 描述的空基类优化条件,但因为它是基类,此项技术的应用不能引入多重继承(参见 Item 40)。反过来说,多重继承有时会使空基类优化失效(还是参见 Item 39)。通常,你可以忽略这些微妙之处,而且此处只是用 Uncopyable 来做演示,因为它比较适合做广告。在 Boost(参见 Item 55)中你可以找到一个可用的版本。那个类名为 noncopyable。那是一个好的 class,我只是发现那个名字有一点儿不(un-)……嗯……非自然(nonnatural)。

Things to Remember

为了拒绝编译器自动提供的功能,将相应的函数声明为 private,而且不要给出实现。使用一个类似 Uncopyable 的基类是方法之一。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有