我正在分析我们的应用程序中发生的访问冲突,因为它试图在其虚函数表指向 0 的对象上调用虚函数。所以我想知道对象生命周期中的哪些点是虚函数表指针未设置或明确设置为零?
(我们使用 Visual C++ 10 作为编译器。)
我正在分析我们的应用程序中发生的访问冲突,因为它试图在其虚函数表指向 0 的对象上调用虚函数。所以我想知道对象生命周期中的哪些点是虚函数表指针未设置或明确设置为零?
(我们使用 Visual C++ 10 作为编译器。)
当对象处于有效状态时,vtable 指针永远不会为 0。在构造和销毁过程中,虽然对象具有抽象基类的动态类型,但 vtable 将指向抽象基类 vtable,其中将包含纯虚函数,但 vtable 指针本身仍将非零。
vtable 指针唯一可以为零的时间是在构造之前或销毁之后。
如果 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.
}
};