Effective C++条款06:构造/析构/赋值运算之(若不想使用编译器自动生成的函数,就该明确拒绝)

Fawziya ·
更新时间:2024-11-10
· 914 次阅读

一、前言 在前面一篇文章中(https://blog.csdn.net/qq_41453285/article/details/104165762),我们介绍了C++编译器会为我们的class生成默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符 但是有些情况下,我们不希望使用其中的一种功能。例如:我们不希望使用class的拷贝赋值运算符(那么就不能将一个对象赋值给另一个对象),那么就需要使用一些手段来禁止使用这些功能 文本介绍一些方法来禁止编译器为我们提供的这些默认函数 二、方式① 如果我们不想使用某些函数,将这些不想使用的函数在类中声明为private,那么就不能使用这些函数了 注意事项: 如果声明为private的话,那么就只需要声明就行了,不需要定义,因为我们程序是不会使用到这些函数的 如果将拷贝构造函数声明为private从而不想使用它,那么我们就必须显式给出构造函数。原因:如果不给出构造函数,那么在定义对象时,对象会将以为拷贝构造函数为构造函数而调用它,但是它是private,从而不允许定义对象 演示案例如下:
class A
{
public:
    A() {} //必须显式定义构造函数,如果不定义那么就不能定义对象
private:
    //只需要声明即可,因为我们不会使用到这两个函数了(并且也不需要给出参数)
    A(const A&);
    A& operator=(const A&);
};
A a;     //正确(如果不定义构造函数,那么a会以拷贝构造函数进行初始化)
A a2(a); //错误(拷贝构造函数为private)
a2=a;    //错误(拷贝赋值函数为private)

“只声明而不定义”的不安全性
上面我们说过如果将其声明为private之后,那么可以之声明而不定义它们
	但是这个方法不是绝对安全的:
	因为如果类的成员函数或friend函数中调用它们,即使是private的,也可以成功调用
		又假设如果我们希望类的成员函数或friend函数调用它们,但在调用时会发现只有声明而无定义,因此链接时会错误
	在C++ iostream程序中的应用:这种手法被用在C++ iostream程序库中阻止拷贝行为。如果查看ios_base,basic_ios和sentry的源码会发现,它们的拷贝构造函数和拷贝赋值运算符都被声明为private且没有定义
三、方式②前一篇文章的最后我们已经介绍过这一种情况,此处我们详细讲解(前一篇文章参阅:https://blog.csdn.net/qq_41453285/article/details/104165762)
	方式①介绍的方法是不安全:因为如果在类的成员函数或friend函数中调用它们,即使是private的,也可以成功调用
	方式②如下:
	是在基类中将这些方法声明为private,然后继承于这个类,那么基类在使用这些函数时也不可以使用
		在类的成员函数或friend函数中调用它们也会产生错误(因为基类的private函数在子类中是不可以使用的)
演示案例
我们专门为了阻止拷贝动作设计了一个Uncopyable基类,然后将自己的类继承于这个类
class Uncopyable
{
public:
    Uncopyable() {}
    ~Uncopyable() {}
private:
    //声明为private
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};
class A :public Uncopyable
{
    //...
};
这种方法的好处:
	①无论以何种方式(public、protected、private)继承于Uncopyable都可以
		②Uncopyable的析构函数不一定得定义为virtual
		③Unable不含数据,符合条款19所描述的“empty base class optimization”
四、Boost库的noncopyable类
Boost库的noncopyable类与上面“三”中介绍的Uncopyable类类似。详情可以自行查阅
五、总结
为了不使用编译器自动提供的功能,可将相应的成员函数声明为private并且不予实现。使用像上面介绍的Uncopyable的机制

作者:江南、董少



自动 c+ 编译器 函数 C++ 赋值

需要 登录 后方可回复, 如果你还没有账号请 注册新账号