22

我读到很多人在写“一个虚拟表存在于一个类中,该类中声明了一个虚函数”。

我的问题是,vtable 是否只存在于具有虚函数的类,或者它是否也存在于从该类派生的类。

例如

class Base{
    public:
        virtual void print(){cout<<"Base Print\n";}
};
class Derived:public Base{
    public:
        void print(){cout<<"Derived print\n";}
};

//From main.cpp 
Base* b = new Derived;
b->print();

问题:如果没有用于派生类的 vtable,那么输出就不会是“派生打印”。因此,IMO 对于任何声明了虚函数的类以及从该类继承的类都存在一个 vtable。它是否正确 ?

4

4 回答 4

19

就仅考虑特定于虚函数的功能而言,在实现 vtable 的传统方法中,当且仅当该派生类覆盖至少一个虚函数时,派生类将需要一个单独版本的 vtable。在您的示例中,Derived覆盖 virtual function print。由于Derived有自己的版本print,所以 vtable 中对应的条目与Derivedvtable 中的对应条目不同Base。这通常需要为Derived.

如果Derived根本不覆盖任何东西,形式上它仍然是一个单独的多态类,但为了使其虚函数正常工作,我们也可以简单地重用Basevtable Derived。因此,从技术上讲,不需要为Derived.

然而,在实际实现中,我们通常称为“vtable”的数据结构通常还包含一些额外的特定于类的信息。这些额外的信息是如此特定于类,以至于大多数时候不可能在层次结构中的不同类之间共享 vtable,即使它们使用相同的一组虚函数。例如,在一些实现中,存储在每个多态对象中的 vtable 指针指向还存储关于类的所谓“RTTI 信息”的数据结构。出于这个原因,在大多数(如果不是全部)实际实现中,每个多态类都有自己的 vtable,即使存储在这些表中的虚函数指针碰巧是相同的。

于 2010-01-31T23:05:58.630 回答
3

是的,你的理解是正确的。任何具有带有任何虚函数的基类的类都有一个 vtable。

于 2010-01-31T21:49:57.820 回答
3

对,是真的。实际上,给定基地的定义:

class derived:public base{
public:
 void print(){cout<<"derived print\n";}
};

完全等价于:

class derived:public base{
public:
 virtual void print(){cout<<"derived print\n";}
};

...因为您已经在基础中将 print 定义为虚拟。

我希望编译器会强制执行...

于 2010-01-31T21:56:04.683 回答
2

是的,这是真的。类从其基类继承所有数据成员,包括 vtable。但是,vtable 条目会相应调整(例如,如果类覆盖基类虚拟方法,则 vtable 中的相应条目必须指向其自己的实现)。

但请记住,“vtable”的概念是几乎每个编译器都使用的常见做法,但它不是强制性的,也不是标准化的。

于 2010-01-31T21:49:26.080 回答