C++ 禁止拷贝 uncopy---摘自effective c++

原创 2011年04月25日 16:27:00

禁止拷贝class一般的方法就是把拷贝构造函数和赋值函数定义为私有函数,一下摘自effective c++:

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

class HomeForSale { ... };

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

HomeForSale h1;

HomeForSale h2;

HomeForSale h3(h1);               // attempt to copy h1 — should
                                  // not compile!

h1 = h2;                          // attempt to copy h2 — should
                                  // not compile!

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

这就限制了你。如果你不声明 copy constructor(拷贝构造函数)或 copy assignment operator(拷贝赋值运算符),编译器也可以替你生成它们。你的 class(类)还是会支持 copying(拷贝)。另一方面,如果你声明了这些函数,你的 class(类)依然会支持 copying(拷贝)。而我们此时的目的却是 prevent copying(防止拷贝)!

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

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

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

class HomeForSale {
public:
  ...

private:
  ...
 
HomeForSale(const HomeForSale&);            // declarations only
 
HomeForSale& operator=(const HomeForSale&);
};

你会注意到,我省略了 functions' parameters(函数参数)的名字。这不是必须的,只是一个普通的惯例。毕竟,函数不会被实现,更少会被用到,有什么必要指定参数名呢?

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

link-time error(连接时错误)提前到编译时间也是可行的(早发现错误毕竟比晚发现好),通过不在 HomeForSale 本身中声明 copy constructor(拷贝构造函数)和 copy assignment operator(拷贝赋值运算符)为 private,而是在一个为 prevent copying(防止拷贝)而特意设计的 base class(基类)中声明。这个 base class(基类)本身非常简单:

class Uncopyable {
protected:                                   // allow construction
  Uncopyable() {}                            // and destruction of
  ~Uncopyable() {}                           // derived objects...

private:
  Uncopyable(const Uncopyable&);             // ...but prevent copying
  Uncopyable& operator=(const Uncopyable&);
};

为了阻止拷贝 HomeForSale objects(对象),我们现在必须让它从 Uncopyable 继承:

class HomeForSale: private Uncopyable {      // class no longer
  ...                                        // declares copy ctor or
};                                           // copy assign. operator

这样做是因为,如果有人——甚至是 member(成员)或 friend function(友元函数)——试图拷贝一个 HomeForSale objects(对象),编译器将试图生成一个 copy constructor(拷贝构造函数)和一个 copy assignment operator(拷贝赋值运算符)。就 Item 12 解释的,这些函数的 compiler-generated versions(编译器生成版)会试图调用 base class(基类)的相应函数,而这些调用将被拒绝,因为在 base class(基类)中,拷贝操作是 private(私有)的。

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

C++ 禁止拷贝 uncopy---摘自effective c++

禁止拷贝class一般的方法就是把拷贝构造函数和赋值函数定义为私有函数,一下摘自effective c++:房地产代理商出售房屋,服务于这样的代理商的软件系统自然要有一个 class(类)来表示被出售...
  • arssqz
  • arssqz
  • 2011年04月25日 16:27
  • 3934

HTTP协议详解(版本一)

HTTP协议详解
  • ppdyhappy
  • ppdyhappy
  • 2015年09月29日 17:31
  • 2456

如何禁止C++ 类支持拷贝

如何禁止C++ 类支持拷贝 C++ 编译器默默地为你做了不少工作 当你写下 class Empty {}; //其实等价于 class Empty { public: Empty() { .....
  • u012653791
  • u012653791
  • 2014年06月30日 13:17
  • 1836

C++如何禁止掉对象的复制操作

最容易想到的是将拷贝构造函数与赋值函数声明为private。但是,private只是说外部不能直接调用,但是可以间接通过类的成员函数来调用(通过成员函数与友元函数对其访问)。那么怎么办呢? ----》...
  • a627088424
  • a627088424
  • 2015年05月28日 11:12
  • 1709

emWin Release notes,最新版本为V5.20

看了一下,从V5.12到V5.20的更新。无非是修正一些一般遇不到的bug,增加了一些新的芯片支持。添加了几个widget: tooltip, calendar等。评估了下,暂时不升级。 从M...
  • Ropai
  • Ropai
  • 2013年08月29日 14:07
  • 4923

C++11

转自 https://zh.wikipedia.org/wiki/C%2B%2B11 C++11,先前被称作C++0x,即ISO/IEC 14882:2011,是目前的C++编程语言的正式标准...
  • arau_sh
  • arau_sh
  • 2013年05月08日 21:20
  • 1233

C++11新标准的阻止拷贝方案

C++11新标准下,可以通过将拷贝构造函数和拷贝赋值运算符定义为删除的函数(deleted function)来阻止拷贝。删除的函数是这样一种函数:我们虽然声明了他们,但是不能以任何形式使用他们。 ...
  • y396397735
  • y396397735
  • 2016年07月02日 10:19
  • 1017

C++如何彻底禁止掉对象的复制操作

在面向对象的世界中,有一些对象是需要
  • linqingwu75
  • linqingwu75
  • 2014年11月08日 14:28
  • 2934

(一) HTTP协议详解

一、概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏...
  • zjq001X
  • zjq001X
  • 2016年11月28日 10:20
  • 223

C++ 工程实践(4):二进制兼容性http://blog.csdn.net/Solstice/article/details/6233478

C++ 工程实践(4):二进制兼容性 标签: c++libraryinterfacemfcclass编译器 2011-03-09 10:46 17338人阅读 评论(61) 收藏 举报 ...
  • wangyin159
  • wangyin159
  • 2016年02月10日 18:10
  • 552
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++ 禁止拷贝 uncopy---摘自effective c++
举报原因:
原因补充:

(最多只允许输入30个字)