多重继承中的Vtable实现

3

我无法弄清楚如何为多重继承创建虚函数表的模式。请看以下代码。

// Iam just providing pseudocode model
class A{
  public:
         Vptr[];    // create function pointer 
         virtual void run(){}
         A(){
             this->Vptr[0] = &A::run; // push virtual function address
         }
}

class B{
  public:
         Vptr[];   // create function pointer
         virtual void sleep(){}
         B(){
             this->Vptr[0] = &B::sleep; // push virtual function address
         }
}

class C : public A, public B{
  public: 
         virtual void run(){}
         virtual void eat(){}
          C(){
             this->A::Vptr[0] = &C::run; // update function address since overrided

             // the question is onto which Vptr does eat() entry is stored?
             // this->A::Vptr[1] = &C::eat() OR this->B::Vptr[1] = &C::eat()
          } 
}

在单继承层次结构中,它会将虚函数条目添加到同一个VPTR的末尾,但在多重继承中,它如何决定呢?因为它有两个VPTRs

我建议你避免使用 this-> 语法;直接访问方法和成员(可以节省打字时间)。只有当方法参数和数据成员 名称相同时 ,才需要使用 this-> 语法来区分。 - Thomas Matthews
Vptr 的类型是什么? - Thomas Matthews
我认为由于runeat方法没有重载或覆盖,编译器可以进行优化,不使用虚函数表。 - Thomas Matthews
使用C++11的override关键字,问题可能会变得更加明显。编译器没有问题地确定它必须覆盖A::run(),因为B没有这个函数。但当它确实有一个时,问题就开始了。 - Hans Passant
你需要声明一个ABI。C++本身没有虚拟表的概念;这是一种实现细节! - Lightness Races in Orbit
C++语言标准并没有使用“vtable”这个词。你的实现今天可能会或可能不会使用vtable(与我的实现、或者明天你的实现方式不同)。你为什么需要知道呢? - n. m.
1个回答

3

我假设你的代码实际上是伪代码C++。

但是你的代码是错误的,因为在C++中,vtable是每个类的,而不是每个实例的。每个实例都保存着指向其所属类的vtable的指针。

因此,正确的方式应该是这样的(伪代码C++):

fn_t A::VTable[] = { &A::run };
fn_t B::VTable[] = { &B::sleep };
fn_t C::VTable[] = { &C::run, &C::eat };

A::A()
{
    A::VPtr = A::VTable;
}
B::B()
{
    B::VPtr = B::VTable;
}
C::C()
{
    A::VPtr = C::VTable;
    B::VPtr = B::VTable;
}

正如您所看到的,C有两个VTable,一个继承自A,一个继承自B。第一个被扩充了所有新的虚函数。

如果C要覆盖sleep(),那么它将构建一个新的VTable:
fn_t C::VTableB[] = { &C::sleep };

C::C()
{
    A::VPtr = C::VTable;
    B::VPtr = C::VTableB;
}

在这个例子中,是否需要虚拟表?由于A类B类的方法是独特的,因此编译器可以生成访问C类中声明的A类B类方法的代码,就好像它们在class C中声明一样。 - Thomas Matthews
1
@ThomasMatthews: 我认为是的。首先,你无法确定是否会有 C 的子类。其次,这是多重继承,因此您可能需要在虚拟调用中进行一些 this 调整,因此您将需要一些 vtable thunks - rodrigo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接