Effective C++学习笔记和在面试,工作中的应用

本文探讨了C++中析构函数与虚函数的重要概念,包括如何避免析构时出现野指针、虚函数表的工作原理及注意事项、构造与析构过程中调用虚函数的风险等。对于基类指针指向派生类对象时,强调了基类析构函数声明为虚函数的重要性。

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

条例07:为多态基类声明virtual析构函数

//声明一个基类
class CTimeKeeper{
public:
CTimeKeeper();
~CTimeKeeper();
};
//声明基类的派生类
class AtomicClock:public CTimeKeeper{};
class WaterClock:public CTimeKeeper{};
class SecondClock:public CTimeKeeper{};
//声明一个函数,返回TimeKeeper的指针
//但是函数内部其实是生成TimeKeeper基类的派生类的对象
TimeKeeper* GetTimeKeeper()
{
AtomicClock* pAtomic = new AtomicClock();
return pAtomic;
}
//定义一个TimeKeeper指针
TimeKeeper *pTime = GetTimeKeeper();
...
//释放pTime
delete pTime;
//该章第一点讲的就是这种释放是有问题的
/*
基类的析构函数为non-virtual类型时,可以理解为基类的析构函数跟派生类的析构函数没有关联,基类不知道她在外面有孩子,
这样就会导致delete之后会调用基类TimeKeeper的析构函数,将TimeKeeper的类对象释放掉,
但是GetTimeKeeper中生成的派生类AtomicClock的析构函数不会被调用到,就导致这部分内存成了没娘养的孩子
*/
/*
解决这类问题的方法就是将基类中的析构函数定义为virtual类型,这样当基类被派生类继承之后,如果派生类的析构函数是non-virtual
类型的,那么基类就知道她在外面有个孩子,当她被delete掉时,她会先安顿好自己的孩子,也就是先调用派生类的析构函数,就可以
避免上面那种出现野孩子的情况。


比较专业一点的说法是,C++的类会维护一个虚函数表,这个表中存放的时候虚函数的地址,按照从基类到派生类的顺序存放,当有一个
虚函数被non-virtual函数继承之后,这个non-virtual会查到该表的最前面,所以就会先于虚函数被调用。(派生类的析构函数为virtual时也会插到前面)
本条的关键就是当有基类的指针指向派生类的地址时,这个基类的析构函数用定义为virtual类型的,派生类的析构函数定义为non-virtual类型的。
如果这个基类和派生类的指针指来指去的话,可以把她的析构函数virtual一下来确保派生类的析构函数会被调用。


*/


//该章第二点讲的虚函数表的问题
/*
如果一个类的函数中有虚函数的话,会多生成一个虚函数表来维护这些虚函数,这样会隐性的增加这个类的大小。
*/

校招和社招面试中这个都是很重要的考点,特别是社招面试中,会问虚函数表是在类中的还是类的实例中。

条框8:别让异常逃离析构函数

在析构函数中catch异常之后,程序必须马上结束运行,因为如果程序不马上结束的话,会一边处理异常,一边产生新的异常,这样会导致程序出现未知的问题。这里可以用std::abort()来结束程序。abort可以理解为Linux下的kill -9 。更好的办法是不要让析构函数处理异常,在完成所有正确或不正确的操作之后,再用析构函数把这个类释放掉。

条框9 绝不在构造和析构过程中调用虚函数

这个方面是为了避免开发者最虚函数的执行顺序判断错误,导致构造或析构中的函数执行不是自己设想的函数。这里有个这本书的比较重要的一个原则,避免在河边湿鞋的最好方法就是不到河边走。另一点是虚函数表的执行顺序。虚函数的设计就是为了能够让开发者自定义基类和子类的函数的执行顺序,这里还有个比较容易出错的地方是在析构函数中,这个执行顺序会反过来。

条例10 operator=的操作中return *this

一个类似于潜规则的条例,没有理由。

条例11 operator=操作中,加上“自我赋值”

解决在对自我幅值时,delete会将形参删掉,从而导致异常的问题。从经验中得到的教训,目前C++的string 的=操作都是会先判断一下(this == &param).社招面试中经常遇到手写一个string类,这个条例就是个考点。

条例12  复制对象时勿忘其每一个成分

比较通俗的一个条例,但是也比较容易忽略,主要是深拷贝和浅拷贝要心中有数

条款13  以对象管理资源

像是指针之类的成员变量,在构造函数中申请内存,在析构函数中释放,这样能够保证这块资源得到释放,如果是临时变量要申请内存,可以用智能指针来处理,改变过去自己new delete 的方式,用惯了智能指针之后真的会爱上智能指针。智能指针的交叉,也在面试中被问到过,可以参考这个文章https://blog.youkuaiyun.com/qq_36953135/article/details/76998104

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值