派生的 class VTable 仅具有基础 class 虚函数。派生的 class 虚函数从派生的 class 的 vtable 中丢失

Derived class VTable having only base class virtual functions. The derived class virtual functions are missing from derived class's vtable

这是一个非常基本的例子:

class Base {
public:
    virtual void sayHi() const {}
    virtual void sayHello() {}
    virtual ~Base(){}
};

class Derived : public Base {
public:
    virtual void sayHi() {}
    virtual void sayHello() const {}
};

int main()
{
    Base *b = new Base();
    Base *d = new Derived();
    return 0;
}

Base 的 vptr,在 'b' 中有 Base class 的虚函数。派生 class 对象 'd' 然而,在检查中,仅列出了基类的虚函数。 这里的问题是 而不是 ,为什么函数没有被覆盖,所以这里不需要使用 override 关键字。问题是,为什么特定 class 的 VTable 不包含它自己的虚函数?在这种情况下,为什么 'd' 的 vtable 不包含 D::sayHi 和 D::sayHello? 我愿意接受反对票,但要勇敢地提及并说出原因。

编辑: 我知道这里的 CONSTness 可能看起来不对,但问题不在于覆盖。

这个在VS2012 Update4中专门试用过

这里有不同的函数重载,它们不会覆盖定义的虚函数:

virtual void sayHi() const {}
virtual void sayHello() {}

void sayHi() {}  // non virtual function with a different signature (no const)
void sayHello() const {} // non virtual function with a different signatuere (const)

如果您想避免此类细微错误,请使用关键字 override :如果您认为覆盖基 class 的虚函数的函数具有不同的签名或什至没有exist (e.g.typo...) 编译器会产生错误。

根据您的编辑进行编辑:

我看到您更新了代码,使重载的非覆盖函数也成为虚拟函数。

现在派生函数的 vtable 包含四个不同的函数。但是,通过基指针只能访问定义在基中的虚函数。这就是 MSVC 调试器只显示 2 个的原因:

顺便说一句,调试器似乎总是将 vtable 显示为 Base 的成员。但是如果你查看生成的汇编程序,你会在它的 vtable 中看到派生的 class 的所有虚函数的损坏名称:

您的 Hi 函数不会覆盖基础 class Hi 函数,因为它们的 const 说明符是错误的。 您的 Hello 函数也是如此,尽管相反。 如果您使用 C++11 或更高版本,您可以使用 override 关键字来确保不会发生这种情况。

已经提到您没有覆盖函数,因为您通过添加常量来更改函数签名。

关于您的实际问题: 它将使用来自基 class 的 vtable-pointer 指向它自己的具有不同条目的 vtable。这就是它的工作原理。它 "looks" 类似于基础 class 但行为 "different"。这就是 C++ 中的多态行为。

如果每个派生 class 都添加自己的 vtable,那么 C++ 中的很多东西都会被破坏。多个 vtable 指针只会是一个 class 实例的一部分,它派生自包含虚函数的多个 classes 或使用虚拟继承时。