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

        本篇的目标是要学会一个条款:

        为了驳回编译器自动(暗自)提供的机能(函数),你可以将相应的成员函数声明为private并且不予以实现

        下面不妨我们先来看一段代码:

class HomeForSale
{
	...
};
void test()
{
	HomeForSale h1;
	HomeForSale h2;
	HomeForSale h3(h2);//企图拷贝h2 给 h3
	h1 = h2;//企图拷贝 h2 给h1
}

        这里假定我们的HomeForSale类的对象被认为是独一无二的,那么我们j就不希望这几条拷贝的语句给编译器通过!
        但我们知道,usually,如果你不希望你的class支持or实现某些特定的功能的话,你不声明对应的函数即可。可这个策略对于 copy 构造函数 以及重载的copy assignment 运算符函数而言是无用的。因为在条款5中我们已经指出,if你不去声明它们,那么编译器就会在他们被需要(被调用)的时候自动生成,这似乎把你逼近一个困境,也即if你不去声明 copy 构造函数 以及重载的copy assignment 运算符函数,那么编译器会为你自动产出一份,于是你的class就会支持copying了。但如果你声明它们,那么你的类还是支持copying。但我们这里的目标却是阻止copying!

        通过以上的简单讨论,你是不是很想解决这个问题呢?

于是,在Effective C++ 的条款6中,给我们提供了解决方案

       :将成员函数声明为private并且故意不实现它们

        下面让我们将这一伎俩施加于HomeForSale类:

class HomeForSale
{
public:
	//...
	HomeForSale() {}
private:
	//...
	HomeForSale(const HomeForSale& );
	HomeForSale& operator=(const HomeForSale& );//只有声明
	//注意:
	//这里因为只有函数的声明,因此我并不一定要把参数名称写出来,因为我不定义的话,写出来又有何用呢?
	//当然,你定义的时候参数列表的参数名称必须要写出来!
};
void test()
{
	HomeForSale h1;
	HomeForSale h2;
	HomeForSale h3(h2);//报错!企图拷贝h2 给 h3 是不行的,因为在类外不能访问类内的private下的成员
	h1 = h2;//报错!企图拷贝 h2 给h1 也是不行的,因为在类外不能访问类内的private下的成员
}

        通过以上代码,将copy 构造函数 以及重载的copy assignment 运算符函数 定义在一个基类(父类)中,并把作用域设置为private,可以解决我们的目标问题的一部分。

        但你不妨想一想,有什么语法形式是可以访问到类内的private成员的呢?

        对的,member函数 以及 friend友元函数 可以访问对于类内的private成员。

因此我们说这半个伎俩还不是绝对安全的,因此下面我们要介绍另一半伎俩

        把想阻止的 copy 构造函数 以及重载的copy assignment 运算符函数 定义在一个基类(父类)中,并把属性设置为private,然后再让一个类去继承这个不可以进行以上操作的基类,这样用这个类所创建的对象都可以达成uncopy的目的了。

        且往下看:

class Uncopyable
{

protected:
	//这个默认的构造和析构函数是为了 允许 子类(派生类)的对象的构造和析构的
	Uncopyable(){}
	~Uncopyable() {}
private:
	Uncopyable(const Uncopyable&);
	Uncopyable& operator=(const Uncopyable&);//但阻止子类(派生类)对象的copying
};
class HomeForSale:public Uncopyable
{
public:
	friend void copyHomeForSaleFun();
	//...
	//HomeForSale() {}
private:
	//...
	//HomeForSale(const HomeForSale& );
	//HomeForSale& operator=(const HomeForSale& );//只有声明
	//注意:
	//这里因为只有函数的声明,因此我并不一定要把参数名称写出来,因为我不定义的话,写出来又有何用呢?
	//当然,你定义的时候参数列表的参数名称必须要写出来!
};
void copyHomeForSaleFun()
{
	cout << "这是HomeForSale的friend友元函数被调用了!" << endl;
	HomeForSale hh1,hh2,hh3;
	hh1 = hh2;//报错!
	//因为当HomeForSale的对象试图拷贝时 都必须要先调用父类(基类)的构造函数,
	//又因为父类的上述函数都是private的,因此你即便是友元函数也无法访问起父类的"隐私"private成员!
	HomeForSale hh3(hh1);//报错!理由同上!
}
void test()
{
	HomeForSale h1;
	HomeForSale h2;
	HomeForSale h3(h2);//报错!企图拷贝h2 给 h3 是不行的,因为在类外不能访问类内的private下的成员
	h1 = h2;//报错!企图拷贝 h2 给h1 也是不行的,因为在类外不能访问类内的private下的成员
}

        由于继承后,子类的对象在进行创建和拷贝赋值操作时都必须要先调用父类(基类)的上述函数,基于此,friend友元函数也无法访问父类的"隐私"的private成员!

对于在C++继承中,父类和子类的构造、析构、拷贝赋值运算符函数的调用顺序的认识icon-default.png?t=L892https://blog.csdn.net/weixin_44980842/article/details/120384907

(当然,我不论你这里是何种继承方式,继承后的类中的成员都是无法访问其父类的"隐私"private成员的!)

        即便是member成员函数,也会报错!理由与上述代码的报错无差!

        就比如在类中添加一个member函数:

	void MyFunc() {
		cout << "这是member函数的调用!" << endl;
		HomeForSale hhh1, hhh2;
		hhh2 = hhh1;
		HomeForSale hhh3(hhh1);//报错!
	//因为当HomeForSale的对象试图拷贝时 都必须要先调用父类(基类)的构造函数,
	//又因为父类的上述函数都是private的,因此你即便是member函数也无法访问起父类的"隐私"private成员!
	}

        综上,我相信你已经理解并学会使用这个条款了。

总结:

        为了驳回编译器自动(暗自)提供的功能(函数),你可以将相应的实现这些功能的成员函数声明为private并且不予以实现。若为了更加安全的达成这一目标,我们会使用一个像Uncopyable这样的base class!

参考:

Effective C++ 之条款06

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fanfan21ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值