打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C++析构函数和virtual函数引发的隐晦问题
用工厂模式的时候,我们常常将一个基类指针指向子类对象,以此来实现多态。但是,当调用delete析构这个基类指针的话,就有一个潜藏的危机:当子类对象经由一个基类指针被删除,而该基类带着一个非virtual析构函数,其结果是不能预料的——实际执行时通常发生的是对象的子类成分没有被销毁!
消除这个问题的做法很简单:给基类一个virtual析构函数

如果一个类不含有virtual函数,通常表示它并不是准备被作为基类。不要为这样一个类也加上virtual函数!否则一来增加运行开销,二则因为vbr的加入使得对象体积变大,还会使得对象内部的细节混乱,无法和其他语言的函数通信。
经验是这样:1 只有当类中含有virtual函数时,我们才为它声明virtual析构函数。2 不带virtua;析构函数的指针的类最好别做基类。3 不要试图继承一个标准容器或任何其他带有非virtual析构函数的类。

当你想拥有一个抽象类,但是没有纯虚函数时,怎么办?
答案是为这个类声明一个纯虚的析构函数,然后再为这个析构函数提供一份定义(因为析构子类时必须要调用它)。这个规则只是针对于那些设计目的为了多态的类。
忠告:


带有多态性质的基类应该声明一个virtual析构函数,如果一个类有任何的virtual函数,它就应该拥有一个virtual
析构函数。

如果类的设计目的不是为了作为基类使用,或者不是为了具备多态性,就不应该声明virtual析构函数。


在类的析构函数抛出异常时,程序可能过早结束或者出现不明确行为(资源泄露)。C++不喜欢析构函数抛出异常!
常规的办法:如果捕捉到析构函数异常,就强制推出程序,避免不明确行为传播。2 忽略异常(捕捉到异常不做任何事)。
较好的方法:写一个普通函数来做析构函数的事情,然后在析构函数里调用这个函数。允许用户调用Close(即使用户不显式调用,也会在析构函数里隐式调用),这样就给了用户一个处理可能出现的异常的机会。

忠告:

析构函数绝对不要抛出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后忽略或者强制程序结束。

如果客户需要对某个操作函数运行期间排除的异常做出反应,那么应该提供一个普通函数(而不是在析构函数中)执行该操作。


如果你想要在构造函数中调用virtual函数,你不会得到你想要的结果。基类构造期间virtual函数绝不会下降到子类。对象的作为就像是基类一样。实际上,在基类构造期间,virtual函数不是virtual函数。因为在基类构造的时候,子类成分还没有构造,怎么可能有函数供调用!
同样的道理适合于析构函数。假如在基类的析构函数中调用了virtual函数,执行的时候其实子类成分已经被析构掉了。

唯一能够避免此问题的做法就是:确定你的构造函数和析构函数的整个执行过程中都没有调用virtual函数。

如果你想要实现一些成员的多态化构造,应该又子类像父类的某些函数传递一些信息,然后由这些函数来进行多态构造,而不是弄一些virtual函数在构造函数里。“由于你无法使用virtual函数从基类向下调用,在构造期间,你可以令子类将必要的构造信息向上传递到基类构造函数中。”

忠告:

在构造和析构期间不要调用virtual函数,因为这类调用从不下降到子类中。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C++中的多态性问题
析构函数virtual与非virtual区别
1-50
虚函数
探索C 虚函数在内存中的表现形式及运行机制(一)
关于类继承的构造与析构调用分析
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服