Effective C++

chapter 2. 构造 / 析构 / 赋值运算

(Constructors, Destructors, and Assignment Operators)

Item 6. 若不想使用编译器自动生成的函数,就该明确拒绝

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

地产中介商卖的是房子,一个中介软件系统自然而然想必有个 class 用来描述待售房屋:

class HomeForSale { ... };

地产商都认为每一笔资产都是独一无二的,因而为 HomeForSale 对象做一份副本有点没道理。因此应该乐意看到 HomeForSale 的对象拷贝动作以失败收场:

HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1);             //企图拷贝 h1  — — 不该通过编译
h1 = h2;                        //企图拷贝 h2  — — 也不该通过编译

阻止这一类代码的编译并不是很直观。通常如果不希望 class 支持某一特定机能,只要不声明对应函数就行。但这个策略对 copy 构造函数和 copy assignment 操作符却不起作用,因为 Item 5 已经指出,如果不声明而尝试调用它们,编译器会声明它们。

这便遇到一个困境。如果不声明 copy 构造函数或 copy assignment 操作符,编译器可能为你产出一份,于是你的 class 支持 copying。如果声明它们,你的 class 还是支持 copying。但这里的目标却是要阻止 copying!

答案的关键是,所有编译器产出的函数都是 public。为阻止这些函数被创建出来,得自行申明它们,但这里并没有什么需求使你必须将它们申明为 public。因此你可以将 copy 构造函数或 copy assignment 操作符申明为 private。藉由明确申明一个成员函数以阻止编译器暗自创建其专属版本;而令这些函数为 private,使你得以成功阻止人们调用它。

一般而言这个做法并不绝对安全,因为 member 函数和 friend 函数还是可以调用 private 函数。除非你不去定义它们,那么如果某些人不慎调用任何一个,会获得一个连接错误 (linkage error )。“将成员函数声明为 private 而且故意不实现它们”这一伎俩是如此为大家接受,因而被用在 C++ iostream 程序库中阻止 copying 行为。这个伎俩施行与 HomeForSale 也很简单:

class HomeForSale
{
public:...
private:...HomeForSale (const HomeForSale &);        //只有声明HomeForSale& operator= (const HomeForSale &);
};

有了上述 class 定义,当客户企图拷贝 HomeForSale 对象,编译器会阻挠他。如果你不慎在 member 函数或者 friend 函数之内那么做,轮到连接器发出抱怨。

将连接期错误转移至编译器是可能的(而且那是好事,毕竟俞早侦测出错误愈好),只要将 copy 构造函数和 copy assignment 操作符申明为 private 就可以办到,但不是在 HomeForSale 自身,而是在一个专门为了阻止 copying 动作而设计的 base class 内。这个 base class 非常简单:

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

为求阻止 HomeForSale 对象被拷贝,我们唯一需要做的就是继承  Uncopyable:

class HomeForSale: private  Uncopyable       //class 不再申明 copy 构造函数或 copy assignment 操作符
{...
};

这行得通,因为任何(甚至是 member 函数或 friend 函数)尝试拷贝 HomeForSale 对象,编译器便试着生成一个 copy 构造函数和一个 copy assignment 操作符,而正如 Item 12 所说,这些函数的“编译器生成版”会尝试调用其 base class 的对应兄弟,那些调用会被编译器拒绝,因为其 base class 的拷贝函数是 private。

Uncopyable class 的实现和运用颇为微妙,包括不一定得以 public 继承它(见 Item 32 和 Item 39),以及  Uncopyable 的析构函数不一定得是 virtual (见 Item 7)等等。 Uncopyable 不含数据,因此符合 Item 39 所描述的 empty base class optimization 资格。但由于它总是扮演 base class,因此使用这项技术可能导致多重继承(因为你还可能继承其他 class,多重继承见 Item 40),而多重继承有时会阻止 empty base class optimization (再次见 Item 39)。通常可以忽略这些微妙点,只像上面那样使用 Uncopyable,因为它完全像“广告”所说的能够正常运行。也可以使用 Boost(见 Item 55) 提供的版本,名为 noncopyable 的 class。

请记住

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

转载于:https://www.cnblogs.com/VVingerfly/p/4639493.html

Effective C++ 之 Item 6 : 若不想使用编译器自动生成的函数,就该明确拒绝相关推荐

  1. C++若不想使用编译器自动生成的函数,就该明确拒绝

    C++若不想使用编译器自动生成的函数,就该明确拒绝 为什么要拒绝? 将copy构造函数或copy assignment操作符声明为private,并且不定义 使用delete(C++11 ) 为什么要 ...

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

    为驳回编译器自动提供的功能,可将相应的成员函数声明为private并且不予实现. 使用像Uncopyable这样的base class也是一种做法(即先声明一个基类,然后私有继承它).这其实有点像使用 ...

  3. Effective C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就 ...

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

    如果自己定义的类中并不需要copy assignment操作符或者copy构造函数,为了避免编译器自动生成 因为编译器自动生成的没什么用,一般是按照顺序进行赋值或者拷贝,对于有对象内含有指针的话可能会 ...

  5. [EffectiveC++]item06:若不想使用编译器自动生成的函数,就该明确决绝

    转载于:https://www.cnblogs.com/jeanschen/p/3224542.html

  6. Effective Modern C++ Item 27 熟悉依万能引用型别进行重载的替代方案

    Item 27 熟悉依万能引用型别进行重载的替代方案 Item 26说过,万能引用和重载在一起总会产生各种各样的问题,无论是独立函数,成员函数,都最好不要和万能引用放一起重载,其中构造函数和万能引用放 ...

  7. More Effective C++之 Item M30:代理类

    虽然你和你的亲家可能住在同一地理位置,但就整个世界而言,通常不是这样的.很不幸,C++还没有认识到这个事实.至少,从它对数组的支持上可以看出一些迹象.在FORTRAN.BASIC甚至是COBOL中,你 ...

  8. More Effective C++之 Item M33:将非尾端类设计为抽象类

    假设你正在从事一个软件项目,它处理动物.在这个软件里,大多数动物能被抽象得非常类似,但两种动物--晰蜴和小鸡--需要特别处理.显然,晰蜴和小鸡与动物类的联系是这样的: 动物类处理所有动物共有的特性,晰 ...

  9. Django项目中的子项目中自动生成自己想要的文件内容

    当我们用命令生成子项目时,会自动生成一些文件,如下图所示: 那为什么会自动生成这些文件呢? 原因如下: 那么如何自动生成我们自己想要的文件呢? 可以直接在app_template文件夹中新建文件,然后 ...

最新文章

  1. 最强 NLP 预训练模型库 PyTorch-Transformers 正式开源:支持 6 个预训练框架,27 个预训练模型...
  2. 解决Error response from daemon: Get https://registry-1.docker.io/v2/library/hello-world/manifests/
  3. HTML5对音频的支持
  4. python画一颗心_利用python画一颗心的方法示例
  5. 20160411作业
  6. Python排序算法(二) 快速排序、希尔排序、归并排序
  7. 幸好权健AI还没落地!一个腕表顶中医,18个关键点就能刷脸
  8. 如何在 Pr 2020中使用音轨混合器?
  9. CT影像数据(nrrd文件和dicm文件)的读取和预处理
  10. matlab绘制二元一次函数图像_二元一次函数曲线拟合的Matlab实现.pdf
  11. 微信小程序弹框wx.showToast、wx.showModal样式修改
  12. 他说,我可能以后不干安全了
  13. XYplorer设置-右键新建word文档或者md文档
  14. html5 xml在线编辑,XML 编辑器
  15. WPF技巧(5)元素的加载与卸载(Loaded and Unloaded)
  16. 会议panel是什么意思中文_医学术语中的panel到底是什么意思
  17. LVI-SAM imageProjection.cpp 代码阅读 附录
  18. informatica 许可_Informatica安装及使用文档
  19. 白光干涉仪和共聚焦显微镜的区别
  20. 关于添加SATA驱动的回复(XP安装时分两个阶段)

热门文章

  1. VC6安装错误——Error Launching ......acmboot.exe
  2. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)...
  3. POJ1236 Network of Schools【强连通】
  4. 华为荣登2015年VoIP和IMS市场榜首
  5. vue2.0transition过渡的使用介绍
  6. 淘宝npm镜像使用方法
  7. Java基础—IO流
  8. PHPExcel处理导入导出图片,链接
  9. 十种方法保持云中数据安全
  10. 简单比较搜索引擎与推荐系统