具有虚拟功能的基础,Derived也有一个这样的虚拟功能,
class Base
{
private:
int i;
public:
Base(int data = 9):i(data)
{
cout << "In Base class constructor" << endl;
}
void display()
{
cout << "In Base class" << endl;
cout << "i = " << i << endl;
}
virtual ~Base()
{
cout << "In Base class destructor" << endl;
}
};
class Derived: public Base
{
private:
int j;
public:
Derived(int data = 10):Base(11),j(data)
{
cout << "In Derived class constructor" << endl;
}
virtual void display()
{
cout << "In Derived class" << endl;
cout << "j = " << j << endl;
}
~Derived()
{
cout << "In Derived class destructor" << endl;
}
};
现在在gdb中我看到Derived类对象的总大小是16个字节(int + int + _vptr + _vptr),但是当我在gdb中打印每个对象时我感到困惑,对于基类它显示为这样
$1 = {_vptr.Base = 0x401010, i = 11}
这很好,但是对于派生它显示的是这样的
$2 = {<Base> = {_vptr.Base = 0x401010, i = 11}, j = 10}
我没有看到派生类的虚拟指针。根据我的理解,除了继承的基类虚拟指针之外,派生类中还应该有一个虚拟指针指向它自己的虚拟表。我在这里做错了什么还是有其他方法可以得到它?
答案 0 :(得分:4)
派生类有自己的vtable
。因此,该类型的对象具有指向它的单个指针。 vtable
包含指向Base
成员函数的条目(如果它们未被覆盖)。因此,在Base
类型的对象中不需要指向Derived
vtable的指针。
_vptr.Base
中出现Derived
的原因是因为您没有覆盖任何功能。编译器不为vtable
生成Drived
,因为它只是Base
的副本。
答案 1 :(得分:1)
使用单继承,通常只有一个虚函数指针:它指向类似函数指针数组的东西。基类提供的条目数是已知的,派生类只是将自己的虚函数标记到最后。
当然,虚函数表实际上如何工作完全取决于各自的ABI。您可以查看,例如,在Linux上使用的Itanium C++ ABI,也可能在其他系统上使用。
答案 2 :(得分:1)
派生类没有指向其vtable的单独的附加指针 - 而是从基类继承的vtable指针将被覆盖以指向派生类的vtable作为派生类的构造函数运行(后来在析构函数运行时还原)。
这样,当在Base*
或Base&
上对嵌入在构造的派生对象中的Base
成员进行操作时,指向VDT的指针(通常偏移到Base
对象)允许调度派生类的方法。