实用经验 63 不使用编译器自动生成的函数,就明确拒绝之

通常,如果你不需要class提供某种机制,你只要不声明对应的函数就OK了。但拷贝构造和拷贝复制对这种做法具有免疫力。即如果你不声明拷贝构造和拷贝赋值,编译器也会高兴的帮你实现他们,而且它还是一个“活雷锋”,帮你实现了也不通知你。虽然编译器的这种策略,在大多数情况下是合理的,但是在某些情况下,我们是不需要这个“活雷锋”的。

我们被编译器逼到了一个困境,如果你不声明拷贝构造或拷贝赋值,编译会默认为你产生一份,于是你的class就支持bit拷贝了,但是如果你自己声明了拷贝构造或拷贝赋值呢?你的class还是没有逃过支持bit拷贝的命运。问题是如何才能真正避免拷贝构造和拷贝赋值呢?

如何避免拷贝构造和拷贝赋值,看下面的几种方法。

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

(2)一般而言这个做法并不绝对安全,因为member 函数和friend 函数还是可以调用你的private 函数。除非你够聪明,不去定义他们,即:只声明,不定义。

我们看下面避免拷贝构造和拷贝赋值的例子:

class User
{
private:
	User(const User&); //只有声明,不实现
	User& operator=(const User&);
}

或许你注意到了,我没写函数参数的名称。晤,参数名称并非必要,只不过大家总是习惯写出来。这个函数毕竟不会被实现出来,也很少被使用,指定参数名称又有何用?有了上述class 定义,当客户企图拷贝User对象,编译器会阻挠他。如果你不慎在member 函数或friend 函数之内那么做,轮到连接器发出抱怨。

此外,将连接期间发生的错误提升到编译期间也是可能的。而且这还是已经好事。实现这以目标也很简单。你只需要声明private,而不实现就可以了。所以如果你想拒绝编译器偷偷为你生成的函数,这种方法才是最好的方法。因为使用这种方法,你不当可以拒绝编译器默认生成的函数,还可以拒绝客户的调用。而上种方法将函数声明为private属性,同时给予实现。客户依然是可以调用的。看下面禁止任何形式的拷贝的例子:

// 不允许拷贝构造的类实现。
class Uncopy
{
public:
	 //允许derived对象构造和析构
	Uncopy() {}
	virtual ~Uncopy(} {} 
private:
	Uncopy(const Uncopy&}; //禁止拷贝
	Uncopy& operator=(const Uncopy&);
};

这是行得通的,任何客户,甚至是member函数或friend函数,只要尝试拷贝Uncopy对象。就会调用Uncopy的拷贝构造函数。但在会被编译器所拒绝。因为Uncopy的拷贝构造函数没有函数实现。这是编译器无法容忍的。

将类的拷贝构造和拷贝赋值声明为private,可禁止对象拷贝。除此之外,如果将构造函数声明为private还可实现另外的功能,这就是控制对象生成的实例数。鼎鼎大名的单例模式就是采用这种机制实现的。我们看一个单例模式的例子:

class CSingleton
{
public:
virtual ~CSingleton() {}
static CSingleton* GetInstance()
{
	static CSingleton instance;
	return &instance;
}
private:
	CSingleton(){}
};

因为构造函数是private的,我们不能为CSingleton类定义实例,而只能通过static的GetInstance函数接口生成此类的实例。由于GetInstance接口采用static属性,导致生成实例只能为一个。所以最终也就实现类对象单一性的控制了。

请谨记

  • 为禁止编译器自动提供的机制,可将相应的成员函数声明为private并不予以实现。
  • 将类的构造函数声明为private,通过一个static的函数接口实现类的使用。这样可以保证类对象实例的单一性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值