从具有非虚拟父级的虚拟类继承的正确方法
我编写了使用三种类型的测试代码: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;
}
毫不奇怪,输出是:
三::test()
〜一()
除了使每个析构函数都是虚拟的之外,还有什么方法可以解决这个问题吗?或者程序员应该小心不要遇到这种情况吗?我觉得奇怪的是编译时没有任何警告。
I've written this test code that uses three types: struct One
is a normal type with no virtual members, struct Two : One
has a pure virtual function and a virtual destructor, and struct Three : Two
implements Two
's interface.
#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;
}
Unsurprisingly, the output was this:
Three::test()
~One()
Is there any way to fix this other than making every destructor virtual? Or should programmers just be careful not to run into this situation? I find it odd that there's no warning when compiling this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
唯一的“修复”是不通过指向
One
的指针删除对象。这是否是一个常见问题,取决于您的类的使用方式。例如,标准库包含像
unary_function
这样的结构,没有虚拟析构函数,但我们几乎没有看到它像这样被滥用。The only "fix" is not to delete the objects through a pointer to
One
.If this is a frequent problem, or not, depends on how your classes are used. For example, the standard library contains structs like
unary_function
without a virtual destructor, but we hardly ever see it misused like this.delete one
会调用未定义的行为,因为对象的动态类型与静态类型不匹配,并且静态类型没有虚拟析构函数。避免此类问题的通常方法是使析构函数成为公共和虚拟的,或者使析构函数成为受保护的和非虚拟的(在预计以这种方式使用的类上)。
delete one
invokes undefined behaviour, because the dynamic type of the object does not match the static type, and the static type does not have a virtual destructor.The usual way to avoid problems like this is to make destructors be either public and virtual, or protected and non-virtual (on classes that are expected to be used in this way).
你必须小心并把 One 的析构函数设为虚拟。一些编译器确实对此发出警告。
You must be careful and make One's destructor virtual. Some compilers do warn about this.
如果您希望在派生类中使用析构函数,则必须将它们定义为虚拟的。这是唯一的方法。
If you want working destructors in derived classes then you must define them as virtual. It is the only way.