阻止拷贝的三种方式

来源:互联网 发布:淘宝待您处理的违规 编辑:程序博客网 时间:2024/06/05 11:11

有些时候我们在定义一个类的时候不希望其中的拷贝控制成员(拷贝构造和拷贝赋值)起作用,也就是阻止拷贝,这时候可能有人会想,那我们干脆不定义这样的拷贝控制函数不就OK了,但悲催的是如果自己不定义,好心的编译器也会及时的学习雷锋好榜样帮你合成定义,即传说中的合成拷贝构造、合成拷贝赋值。既然如此,应该如何操作实现我们的目的呢,结合effective C++的条款中给出两种方式,而C++11当中也给出了一种,下面由一个例子说起,简单介绍三种阻止拷贝的方式。
有一个房产销售系统类,用来描述待售房屋:

class HomeForSale{...};

每一位房屋销售人员都会号称每一笔房屋资产都是天上地下独一无二,没有两笔完全相像。所以我们也认为,为这个类对象做一份副本有点没道理——怎么能够复制某些先天独一无二的东西呢?所以,HomeForSale对象的拷贝动作以失败收场:

HomeForSale h1;HomeForSale h2;HomeForSale h3(h1);  //此时调用拷贝构造函数h1=h2;           //此时调用拷贝赋值运算符

按照我们所想,代码中的拷贝构造及赋值操作都不应该通过编译,也就是应该阻止这样的拷贝操作,前面已经提到过即使程序员自己不定义拷贝控制成员,编译器也会自行生成默认版本。那么应该怎样做呢。
(1)将拷贝控制成员函数声明为private且不进行定义
这种方式,将拷贝构造函数和拷贝赋值运算符声明为private,阻止了编译器创建合成版本,同时这些private函数也阻止了用户调用。而不对其进行定义,也做到了即使是成员函数和友元也无法进行调用。

//将HomeForSale的拷贝构造和拷贝赋值声明为private且不对其定义class HomeForSale{public:    ...private:    ...    HomeForSale(const HomeForSale&);    //只有声明    HomeForSale& operator=(const HomeForSale&);};

(2)设计一个专门为了阻止拷贝动作的基类,将连接期错误转移至编译器

class Uncopyable{protected:    Uncopyable() {}    ~Uncopyable() {}private:    Uncopyable(const Uncopyable&);    Uncopyable& operator=(const Uncopyable)};

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

class HomeForSale:public Uncopyable{        ...};

这种方式行得通,当尝试拷贝HomeForSale对象,编译器就试着生成一个拷贝构造函数和一个拷贝赋值运算符,而这些函数的编译器合成版会尝试调用其基类的对应成员,那些调用会被编译器拒绝,因为其基类的拷贝函数是private。
(3)将拷贝控制函数定义为“删除的”
在C++11中,通过在函数的参数列表后面加上”=delete”来指出我么希望将它定义为删除的,即虽然声明了它们,但不能以任何方式使用。

class HomeForSale{public:    HomeForSale(const HomeForSale&)=delete;    //定义为删除的    HomeForSale& operator=(const HomeForSale&)=delete;};

析构函数不能是delete的,如果析构函数被删除,就无法销毁此类型的对象了。

原创粉丝点击