C++箴言:拒绝不想用的编译器产生的函数

C++箴言:拒绝不想用的编译器产生的函数,第1张

C++箴言:拒绝不想用的编译器产生的函数,第2张

如果你不想用编译器为你生成的函数,你绝对可以拒绝。

房产中介卖房子,服务于这类中介的软件系统自然有一个类来表示卖出的房子:

销售类主页{...};

每个房地产经纪人都会很快指出,每一处房产都是独一无二的——没有两处是完全一样的。在这种情况下,制作HomeForSale对象的副本的想法令人费解。你如何复制独一无二的东西?让这个复制HomeForSale对象的类似尝试编译失败:

HomeForSale h1
home for sale H2;
HomeForSale H3(h1);//试图复制h1 -应该
//不编译!
h1 = H2;//试图复制h2 -应该
//不编译!


唉,防止这种编译的方法可不是那么简单易懂的。通常,如果你不想让一个类支持某个函数,你可以简单地不声明赋予它这个函数的函数。这个策略对复制赋值操作符不起作用,因为,正如第5项指出的,如果你不声明它们,而有人想调用它们,编译器会隐式声明它们。

这限制了你。如果你没有声明复制构造函数和复制赋值操作符,编译器也可以为你生成。你的类还是会支持复制的。另一方面,如果你声明了这些函数,你的类仍然支持复制。我们的目标是防止复制。解决这个问题的关键是所有编译器生成的函数都是公共的。要防止这些函数生成,必须自己声明,但是没有理由声明为public。相反,复制构造函数和复制赋值操作符应该声明为私有的。显式声明成员函数可以防止编译器生成自己的版本,将此函数声明为私有可以防止其他人调用它。

通常这种方案不是很安全,因为成员函数和友元函数还是可以调用私有函数的。换句话说,除非你不去定义它们。然后,当有人不小心使用它们时,连接时会出现错误。这一招——定义了一个私有成员函数但故意不实现——确实不错。在C++的iostreams库中,有几个类使用这个方法来防止复制。例如,如果您查看您使用的标准库的实现中的ios_base、basic_ios和sentry的定义,您会看到复制构造函数和复制赋值运算符被声明为私有的和未定义的。

对HomeForSale应用这个技巧很简单:

class home for sale {
public:
..
private:
...
home forsale(const home forsale &);//仅声明
HomeForSale & operator =(const HomeForSale &);
};

你会注意到我省略了函数参数的名字。没必要,这只是惯例。毕竟函数没有定义,也很少用到。为什么需要指定参数的名称?

对于上面的类定义,编译器会阻止客户端试图复制HomeForSale对象。如果您在成员函数或友元函数中不小心这样做了,链接器会建议*。

将连接时间错误提前到编译时间也是可行的(毕竟早发现错误总比晚发现好)。不要让HomeForSale单独声明私有的复制构造函数和复制赋值运算符,在专门设计的基类中声明。这个基类本身非常简单:

class un copyable {
protected://allow构造
Uncopyable() {} //并销毁
~Uncopyable() {} //派生的对象...[/ br/] private:
不可复制(const不可复制&);// ...但防止复制
不可复制& operator=(const不可复制&);
};

为了禁止复制HomeForSale对象,我们必须使它从不可复制的对象继承:

class HomeForSale: private不可复制{ // class不再
...//声明copy ctor或
};//复制赋值。操作员

在这里,如果有人——即使是成员函数或友元函数——试图复制HomeForSale对象,编译器将试图生成一个复制构造函数和一个复制赋值操作符。如第12项所述,这些函数的编译器生成版本将尝试调用基类的相应函数,这些调用将被拒绝,因为复制操作在基类中是私有的。

在不可编译的实现和使用中有一些微妙之处。例如,从不可编译的继承不能是公共的(参见第32和39项),并且不可编译的构造函数不必是虚拟的(参见第7项)。由于Uncopyable不包含数据,所以满足第39项描述的空基类的优化条件,但由于是基类,所以该技术的应用不能引入多重继承(见第40项)。反之,多重继承有时会使空基类的优化失效(再次参见第39项)。通常情况下,你可以忽略这些细微之处,这里我们只使用不可复制的进行演示,因为它更适合做广告。你可以在Boost中找到一个可用版本(见第55项)。那个类名是不可复制的。那是一门好课。我只是觉得这个名字有点不-…嗯…不自然。

要记住的事情

拒绝编译器自动提供的函数,将对应的函数声明为私有,不给出实现。使用不可复制的基类是方法之一。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++箴言:拒绝不想用的编译器产生的函数

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情