从具有非虚拟父级的虚拟类继承的正确方法
Posted
技术标签:
【中文标题】从具有非虚拟父级的虚拟类继承的正确方法【英文标题】:Correct way to inherit from a virtual class with non-virtual parent 【发布时间】:2012-02-04 20:33:49 【问题描述】:我编写了这个使用三种类型的测试代码:struct One
是没有虚成员的普通类型,struct Two : One
有一个纯虚函数和一个虚析构函数,struct Three : Two
实现了Two
的界面。
#include <iostream>
struct One
~One()
std::cout << "~One()\n";
;
struct Two : One
virtual ~Two()
std::cout << "~Two()\n";
virtual void test() = 0;
;
struct Three : Two
virtual ~Three()
std::cout << "~Three()\n";
virtual void test()
std::cout << "Three::test()\n";
;
int main()
Two* two = new Three;
two->test();
One* one = two;
delete one;
不出所料,the output was 这个:
三::test() 〜一个()
除了将每个析构函数设为虚拟之外,还有其他方法可以解决此问题吗?还是程序员应该小心不要遇到这种情况?我觉得编译时没有警告很奇怪。
【问题讨论】:
一个简单的解决方法:使用来自One
的私有或受保护继承,并通过使用声明公开功能。
【参考方案1】:
你必须小心,将 One 的析构函数设为虚拟。一些编译器会对此发出警告。
【讨论】:
【参考方案2】:唯一的“修复”是不通过指向One
的指针删除对象。
这是否是常见问题取决于您的类的使用方式。例如,标准库包含像 unary_function
这样没有虚拟析构函数的结构,但我们很少看到它被这样滥用。
【讨论】:
为了强制执行,One
的析构函数应该受到保护【参考方案3】:
如果你想在派生类中使用析构函数,那么你必须将它们定义为虚拟的。这是唯一的方法。
【讨论】:
【参考方案4】:delete one
调用未定义的行为,因为对象的动态类型与静态类型不匹配,并且静态类型没有虚拟析构函数。
避免此类问题的通常方法是使析构函数成为公共和虚拟的,或受保护的和非虚拟的(在预期以这种方式使用的类上)。
【讨论】:
以上是关于从具有非虚拟父级的虚拟类继承的正确方法的主要内容,如果未能解决你的问题,请参考以下文章
当涉及部分虚拟继承时,这是计算创建的基类对象数量的正确方法吗?