【发布时间】:2013-03-26 22:11:47
【问题描述】:
首先,我理解为什么在单继承和通过基指针删除对象方面需要virtual 析构函数。这特别是关于多重继承以及为什么这有效的原因。这个问题出现在我的一堂大学课程中,没有人(包括教授)知道为什么会这样:
#include <iostream>
struct A
{
virtual ~A()
{
std::cout << "~A" << std::endl;
}
int memberA;
};
struct B
{
virtual ~B()
{
std::cout << "~B" << std::endl;
}
int memberB;
};
struct AB : public A, public B
{
virtual ~AB()
{
std::cout << "~AB" << std::endl;
}
};
int main()
{
AB* ab1 = new AB();
AB* ab2 = new AB();
A* a = ab1;
B* b = ab2;
delete a;
delete b;
}
这个的输出是:
~AB~B~A~AB~B~A
在删除a 或b 时,编译器如何知道如何调用A 和B 的析构函数?具体来说,AB的内存是如何布局的(尤其是虚函数表),才能调用A和B的析构函数?
我的教授建议将内存布局(某种东西)如下:
AB
+---------+ +----+
| A VFT | - - - - - -> | ~A |
+---------+ +----+
| memberA |
+---------+ +----+
| B VFT | - - - - - -> | ~B |
+---------+ +----+
| memberB |
+---------+
// I have no idea where ~AB would go...
我们都很好奇这些析构函数实际上是如何在内存中布局的,以及在a 或b 上调用delete 是如何导致正确调用所有析构函数的。删除基础对象在单继承中工作是有道理的(因为有一个单独的虚函数表可以使用),但显然我没有正确理解事物,因为我无法理解单继承版本并应用它到这个多重继承的例子。
那么这是如何工作的呢?
【问题讨论】:
-
嗯,vtable 条目需要指向
~AB,而不是~A或~B... -
@OliCharlesworth:啊,那肯定更有意义。
-
Microsoft C++ 文档有一个很好的虚拟与非虚拟销毁顺序示例msdn.microsoft.com/en-us/library/6t4fe76c.aspx#Anchor_2
-
很简单,首先
B然后A设置析构函数的指针(在它们的构造函数中),但都被AB覆盖,所以,无论你删除哪个,你总是调用同一个析构函数!
标签: c++