我正在分析我们的应用程序中发生的访问冲突,因为它试图在虚函数表指向0的对象上调用虚函数。所以我想知道对象生命周期中的哪些点是虚函数表指针未设置或显式设置为零?
(我们使用Visual C ++ 10作为编译器。)
答案 0 :(得分:3)
当对象处于有效状态时,vtable指针永远不会为0。在构造和销毁期间,当对象具有动态类型的抽象基类时,vtable将指向抽象基类vtable,其将包括纯虚函数,但vtable指针本身仍将是非零。
vtable指针唯一可以为零的时间是在构造之前或破坏之后。
答案 1 :(得分:1)
如果vtable指针真的为零,那么您可能使用了VC ++扩展名,例如:
class __declspec(novtable) Base {
public:
Base();
virtual void proc();
};
这里__declspec(novtable)
告诉编译器该类不需要vtable,因为在派生类安装了自己的vtable之前,不会调用任何虚函数。如果你在发生之前调用Base :: proc(),你可能会收到错误。
vtable本身更可能是非零,但由于函数是纯虚函数,因此函数的插槽为零:
class Base {
public:
virtual void proc() = 0;
};
然后有人用以下代码调用它:
void Derived::proc() {
Base::proc();
// Derived-specific stuff here.
};
这可能发生,因为Derived的作者假设他们的覆盖需要调用Base版本,即使Base版本不存在。
无论哪种方式,找到这种方法的一种方法是停止所有基类的恶作剧,正常定义函数,并查看调用它的内容。例如:
class Base {
public:
virtual void proc() {
assert( typeof(*this) != typeof(Base) ); // Break-point here.
}
};