为什么在析构函数中将虚表设置回该级别
Why in destructors is the virtual table set back to that level?
在大多数派生类的析构函数中调用纯虚函数之后,我尝试了一些代码来检查一些语法,发现在调用连续的析构函数时,它们调用了相关的虚函数。考虑以下代码:
class Base
{
public:
virtual void Method() = 0;
};
class Derived : public Base
{
public:
~Derived()
{
Method();
}
virtual void Method()
{
cout << "D";
}
};
class DoubleD : public Derived
{
public:
~DoubleD()
{
Method();
}
virtual void Method()
{
cout << "DD";
}
};
int main(array<System::String ^> ^args)
{
DoubleD D;
DoubleD E;
return 0;
}
如预期的那样,当对象被析构时,它调用正确的方法(例如首先是最派生的方法,然后是第二个最派生的方法)。
输出:DD D
我的问题是,为什么这个工作?既然您不打算在c'tor/d'tor中调用虚拟函数,那么为什么虚拟表会正确地"展开"呢?
例如,我可以看到为什么最派生的一个工作,这是虚函数指针表在这个开始时的状态。但是,当调用Derived
的析构函数时,为什么表被正确地设置为指向Method
的类实现呢?
为什么不保留它,或者如果它是好的,将值设置为NULL。
由于您不打算在c'tor/d'tor中调用虚函数,为什么虚拟表可以正确地"unwind"?
前提是错误的。从构造函数或析构函数调用虚函数并没有错,只要您知道它们是如何工作的。正如您所看到的,动态类型是正在运行的构造函数或析构函数的类型,因此不会对尚未构造或已经销毁的对象部分进行虚调用。
行为定义得很好。你不应该担心你的编译器供应商是如何实现它的(尽管这并不难自己推理出来,或者只是查找)。
通常不建议在析构函数中调用虚函数,因为它的行为不直观,但它没有根本的问题。
根据标准,它应该是这样工作的。
至于为什么,在为派生类运行析构函数之后,不能指望该类的任何属性是有效或一致的。此时调用虚方法中的一个,如果它进入派生类方法,将是一场灾难。编译器很可能完全绕过虚函数表,因为它已经知道哪个被覆盖的方法应用于对象的当前状态。这只是一个实现细节
在对象创建时初始设置后,虚拟表不会在运行时被修改。在一些实现中,虚拟表应该按照类的基础来创建。
在你的例子中,当double对象被销毁时,它调用double类中的方法函数,因为对象的double部分还没有完全销毁。double类的VTable有一个方法函数的入口,当它被重写(在继承的最后一层)时,它指向类中的方法
一旦double被销毁,现在对象类型为派生类型。所以调用必须去类派生的vtable中的方法。- Qt自定义小部件外观在设置样式表后没有变化
- 无法在 qt 中为 QWidget 中的派生类设置样式表
- 如何在QT中设置样式表以选择假发背景的随机图像
- 为 QWidget 的私有成员设置样式表
- Qt- 设置来自表视图的输入的验证器
- QT Designer-设置样式表 - 现在进行硬编码 - 想要以编程方式设置
- 在 c++ 中,如何远程设置注册表项(连接工作正常,但设置不起作用!
- 如何为自定义形状的Qbutton设置样式表
- 在Qt中为整个小部件设置样式表
- Qt QMenu 设置样式表
- 虚表中虚函数的地址
- 通过虚表接口使用Excel
- 在静态分配对象上调用虚函数时使用的虚表
- 以编程方式为所有用户设置注册表软件策略键
- 为什么在析构函数中将虚表设置回该级别
- 编译一个Qt单文件从命令行:未定义的引用到虚表
- Qt与代码块-未定义的引用虚表
- 在多重继承中,被重写的虚方法保存在c++的虚表中
- 对虚表的未定义引用.Q_OBJECT宏
- 在c++中禁用虚函数的动态绑定(创建虚表)