2

给定以下代码:

namespace Example1 {

class Base1 {
public:
    Base1() {}
    virtual ~Base1() {}
protected:
    float data_Base1;
};

class Base2 {
public:
    Base2() {}
    virtual ~Base2() {}
protected:
    float data_Base2;
};

class Derived : public Base1, public Base2 {
public:
    Derived() {}
    virtual ~Derived() {}
protected:
    float data_Derived;
};

class Derived2 : public Base1 {
public:
    Derived2() {}
    virtual ~Derived2() {}
protected:
    float data_Derived2;
};

}

int main (void)
{
using namespace Example1;

Base2* pbase2 = new Derived;        
Base1* b = new Base1();
      Base1* b2 = new Base1();
Derived* d = new Derived;
Derived* d2= new Derived;

Derived2* dd = new Derived2;
}

使用 Visual Studio 2012 的编译器,似乎在多重继承下,派生类包含 n-1 个附加虚拟表。这正是派生类发生的情况。

但它似乎也发生在 Derived2 (仅继承自 Base1 类)

这是 dd 内存映射:

Example1::Base1
  __vfptr
     [0]     0x00c4127b

这是 b 内存映射:

__vfptr
    [0]      0x00c411ae

可以看到,第一个虚拟表槽的地址是不同的。例如 b 和 b2 具有相同的虚拟表。

好的,现在针对两个问题:

1) 为什么他们不共享同一个 Base1 虚拟表?(Derived2 和 Base1 对象)

2)为什么派生类甚至需要保存 n-1 个虚拟表?(当 N 表示 Derived 类继承自的类数时)

谢谢!

4

2 回答 2

0

每个类都有自己的 vtable。在这种情况下,每个类都有一个唯一的虚拟析构函数,这本身就意味着 vtable 需要不同。如果您要构造一个没有任何不同虚函数的类,编译器可能会决定“重用”同一个 vtable。但不能保证。

如果一个类派生自多个类,那么每个类都需要一个 vtable,它具有任何类型的虚函数。这样一来,如果将类转换(通过使用指向基类的指针或 dynamic_cast)到基类之一,则可以调用两个基类的虚函数。

另请注意:编译器如何处理 vtables 完全取决于编译器,并且不保证它们如何工作的任何方面。

于 2013-05-08T09:37:32.560 回答
0

首先,Derived2它属于另一种类型Base1,因此它需要除虚函数表之外的一些其他信息。其次,至少Derived2' 的析构函数是不同于 from 的另一个函数Base1,因此即使表中只有虚函数,该条目必须不同。我不确定 MSVC 如何在多态类型上实现 RTTI,但必须对与虚函数不同的类型进行一些识别,例如启用dynamic_casts。所以第一个条目很可能是指向 RTTI 的指针。我目前没有 MSVC,但你可以试试这个:

struct Base {
  virtual void foo() {};
  virtual void bar() {};
  virtual ~Base();
};

struct Derived {
  virtual void foo() {};
  virtual ~Derived();
};

int main() {
  Base* b1 = new Base;
  Base* b2 = new Derived;
};

现在检查两个创建的对象的前四个或五个元素__vfptr,我猜你会看到一个相同的条目 - 它是指向Base::bar. 其他的(指向 RTTI、foo 和析构函数的指针)应该不同。
这里有一些猜测:也许您可以在内存中看到指针指向的不同区域,因为 RTTI 指针可能指向数据段,而虚函数指针指向代码段。

更新: vtable 本身不需要 RTTI 条目 - 某些编译器可能仅通过比较vtable 的地址来实现 RTTI。

于 2013-05-08T09:40:48.480 回答