【Effective C++ 读书笔记】第二章

本文探讨了C++中构造、析构及赋值运算的相关规则,包括编译器自动生成函数的行为、如何禁止使用默认函数以及多态基类中虚析构函数的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第二章: 构造/析构/赋值运算

条款5: 了解 C++ 默默编写并调用哪些函数

  • 当 C++ 进行处理之后,一个空类就不再是空类了。因为编译器会为它声明编译器版本的一个 默认构造函数,拷贝构造函数,拷贝赋值运算符 和 析构函数。这些函数都是 public 的且 inline 的。
  • 编译器版本的 默认构造函数和析构函数主要是 调用基类和非静态成员变量 的构造函数和析构函数。编译器产出的 析构函数 是一个 非虚函数,除非这个类的基类自身声明了 虚析构函数。
  • 编译器版本的 拷贝构造函数 和 拷贝赋值运算符 只是单纯地将来源对象的每一个非静态成员变量拷贝到目标对象。
  • 如果一个 类中包含 引用和常量成员,而 C++ 并不允许 让引用或常量 改指向不同对象。面对这个情况,C++的响应是拒绝编译那一行赋值动作。因此我们必须自己定义 拷贝赋值运算符 以处理 支持 内含引用成员以及常量成员 的类 的赋值操作。
  • 如果某个 基类 将拷贝赋值运算符 声明为 私有的,那编译器也将拒绝为其派生类 生成一个 拷贝赋值运算符。

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

  • 如果我们想要 阻止拷贝操作,我们可以将 拷贝构造函数 或 拷贝赋值运算符 声明为 private,这阻止了编译器暗自创建其专属版本。但这个做法并不绝对安全,因为 成员函数以及友元函数 都还是可以调用到这些私有函数。
  • 我们也可以将成员函数声明为私有同时故意不实现它们,这被用在 C++ iostream库中 阻止拷贝行为。
  • 将 拷贝构造函数 以及 拷贝赋值运算符 在一个专门为了 阻止拷贝动作 而设计的基类内 声明为 private:
class Uncopyable{
protected:
	Uncopyable(){}
	~Uncopyable(){}
private:
	Uncopyable(const Uncopyable&);
	Uncopyable& operator=(const Uncopyable&);
};

class HomeforSale : private Uncopyable{
...
}
  • 由于它总是扮演 基类,因此使用这项技术有可能导致多重继承。

条款7: 为多态基类声明虚析构函数

  • 依靠用户来执行 delete操作,基本上就带有某些错误倾向。
  • 基类有一个非虚析构函数,当派生类对象经由一个基类指针被删除,该基类带有非虚析构函数,那其结果就是 实际执行时通常发生的是对象的派生成分没被销毁。这会导致资源泄露,浪费调试时间。
  • 任何 类,只要带有 虚函数 那几乎确定应该也有一个 虚析构函数。
  • 当 类 不企图被当做 基类,令其析构函数成为虚函数往往是个馊主意。(虚函数指针需要额外的内存空间)
  • 虚函数指针 被用来在运行期决定哪一个 虚函数应该被调用,其指向一个由函数指针构成的数组,被称为虚函数表。
  • 包含虚函数的类,其对象体积会增加,同时该对象也不再和其他语言 (如 C) 内的相同声明有着一样的结构 (因为其他语言的对应物中不包含虚函数指针)。因此,无端地将所有类的析构函数声明为 virtual,就像从未声明它们为virtual一样,都是错误的。
  • string,vector,list,set,unordered_map 等 类不含 虚析构函数,我们不能错误地把它们当成基类。
  • 当我们希望拥有抽象类,但手头上没有任何纯虚函数,那解决方法可以是: 为我们希望成为 抽象的类 声明一个 纯虚析构函数。
  • 析构函数的运作方式: 最深层派生的那个类的析构函数最先被调用,然后是其每一个基类的析构函数被调用。
  • 并非所有基类的设计目的都是为了多态用途 (如 string 和 STL容器)。某些类的设计目的是作为基类而不是多态,如之前的 Uncopyable,它们并非被设计用来 经由基类接口 处置 派生类对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值