一个虚析构函数引发的讨论
来源:互联网 发布:linux 卸载chromium 编辑:程序博客网 时间:2024/05/17 02:37
今天同事帮我作code review的时候,提了一个comment: 为什么这个类的析构函数前面不加上virtual, 防止多态析构的时候父类析构函数没有被调到?
我解释说是因为这个类没有其他的虚函数,也没打算让其他类来继承它,如果非要在析构函数前面加个virtual, 这个类还要维护一个虚函数表指针,有点画蛇添足。
接着同事的回答也很有道理:万一这个类被继承了,又刚好是用父类指针的方式析构呢?
我当时的第一反应是:那不是所有C++的类都要加个析构函数了? 后来反应过来,能不能利用一些手段,把这个类限制住,不允许它被继承?
在JAVA中有一个关键字:final, 被final修饰的类或方法不能被用来继承。那C++呢?查了下资料,原来在C++11中,也引入了final关键字,来达到同样的目地。
但是我们这个项目是运行在老版本的C++上的,这又怎么办?
我们知道,派生类对象实例化时,首先要调用基类构造函数,对基类部分对象进行初始化,之后再调用派生类构造函数,对派生类部分的对象进行初始化。那我们能不能像单件那样,对基类的构造函数动一些手脚,来防止它被派生类调用?
后来果然在Stackoverflow上找到了下面的一种方法:
class CSealed { protected: CSealed() {}};class Base : virtual CSealed { public: Base() {} ~Base() {cout << "Base::~Base()" << endl;}};class Derive : public Base { public: Derive() {cout << "derive" << endl;}};
在上面的代码中,class Derive试图继承class Base时,会报编译错误:
error: ‘CSealed::CSealed()’ is protected
从而我们达到了禁止class Base被继承的目的。
为什么Derive会因为CSealed的原因,不能继承Base呢?因为这里利用的虚继承的机制,使得Derive必须要跨过Base,直接去调用CSealed的构造函数,但是又因为CSealed的构造函数是protected的,Derive没有调用权限,从而导致了编译出错。
又由于Base是继承自CSealed的,因此Base对CSealed的构造函数有访问权限。
最后总结一下,这个问题本身就比较tricky。其根源是C++在多态情况下,对类对象进行析构时,不会调用其父类的非虚析构函数陷阱。为了避免踩进这个陷阱,我们又做了一些workaround来在编译器的范围限制它,这也难怪在C++11中会引入final关键字了。
- 一个虚析构函数引发的讨论
- 纠错一个Python程序引发的讨论
- 一个简单C程序引发的讨论
- 由一个贴子引发的讨论
- “高清炮”引发的讨论
- 一个 inline 函数引发的葫芦案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个函数命名所引发的思考
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 一个Sqrt函数引发的血案
- 数据库原理(六)--关系数据理论
- memcimp
- iOS开发之网络编程--4、NSURLSessionDataTask实现文件下载(离线断点续传下载) <进度值显示优化>
- Javascript面向对象编程二
- JAVA 反射机制简单运用
- 一个虚析构函数引发的讨论
- Android逆向分析之APKTool
- 禁止select默认选择
- MTK内存分析
- round、floor、ceil、trunc的对比
- PAT乙级—1004. 成绩排名 (20)-native
- Makefile学习笔记
- zookeeper windows的安装
- Javascript面向对象编程三