【问题标题】:Mechanism of Vptr and Vtable in C++C++中Vptr和Vtable的机制
【发布时间】:2013-10-13 23:37:30
【问题描述】:

在 C++ 中,在动态绑定期间,请考虑以下示例...

class Base
{
  virtual void fun()
  {
     cout<<"Base";
  }      
};

class Derived : public Base
{
   void fun()
   {
     cout<<"Derived";
   }
};

int main()
{
  Base *bptr;
  Derived d;
  bptr=&d;
  bptr->fun();
}

由于声明了虚拟关键字/动态绑定,上述函数的输出为“Derived”。

根据我的理解,将创建一个包含虚拟函数地址的虚拟表 (Vtable)。在这种情况下,为派生类创建的虚拟表指向继承的虚拟fun()。而bptr-&gt;fun() 将被解析为bptr-&gt;vptr-&gt;fun();。这指向继承的基类函数本身。派生类函数是怎么调用的,我不是很清楚?

【问题讨论】:

  • 请注意,它是int main,而不是void main,并且类声明需要以; 结尾。
  • 下面的答案看起来不错,但如果您觉得需要阅读更多有关该主题的内容,我建议您 Inside the C++ Object Model(ISBN:978-0201834543)。

标签: c++ virtual-functions dynamic-binding


【解决方案1】:

刚刚通过此链接virtual table and _vptr

它说工作流程会像..

  1. base_ptr->base_vptr---->检查基类中虚函数的访问。

  2. base_ptr->derived_vptr->virtual_function()--->调用/调用虚函数。

因此调用了派生类虚函数。希望对您有所帮助。

【讨论】:

  • 已引用此链接...不提供完整的解决方案。您的第 2 点说将调用虚函数,这就是问题所在。但在这种情况下,必须调用derived。
  • @BlueDiamond: base_ptr->derived_vptr->virtual_function()---> 在派生类中调用/调用虚函数。基类指针将包含派生虚拟指针(派生类虚拟指针指向派生类虚拟表)。然后在调用虚函数时派生虚指针,派生类虚函数被调用。
  • 派生虚函数不应该被调用。派生类虚函数是从基类继承的。被覆盖的函数应该被调用...
  • @BlueDiamond,如果你没有在派生类中定义虚函数,那么将调用基类虚函数,但是由于你是覆盖它,所以这里调用了派生类虚函数。
  • @SantoshSahu 这是否意味着每个派生类都有自己的 vptr ,还是 vptr 从基类继承到派生类?
【解决方案2】:

而 bptr->fun() 将被解析为 bptr->vptr->fun();。这指向基类函数本身。

错了。 Derived 实例的 vptr(每个实例中的隐藏字段)指向 Derived vtable。

【讨论】:

  • 好的,所以你明白每个类都有自己的 vtable(说明每个虚拟方法应该使用哪个实现)并且每个实例的 vptr 指向正确的 vtable,匹配对象的实际(动态)类型。缺少什么?
  • 也许缺少的链接是 Derived 的 fun 也是(隐式)虚拟的?这是隐含的,因为 fun 类型签名是相同的。
  • Vtable 只包含虚函数的地址。但是如何调用派生函数呢? vtable不包含非虚函数的地址..
  • 非虚拟函数显然是在编译时选择的。在您提供的代码中,派生的fun 也是虚拟的(implicitly),因为在基类中有一个具有相同签名的virtual fun。更改名称或添加参数,看看会发生什么。
  • 上面的代码给出了预期的 o/p。但我不清楚深入的机制。派生类中有两个具有相同名称/签名的函数。比如说,一个是继承的 virtual fun(),另一个是覆盖的 non virtual fun()。派生类 V-table 只包含继承的 virtual fun() 的地址吗?那么另一个函数是如何被调用的,即非虚函数呢?
【解决方案3】:

标准没有指定实现多态性的机制。标准所说的只是它应该如何工作,而不是编译器供应商应该如何实现它。

话虽如此,就 Linux 下的 GCC 和 Windows 下的 MSVC 而言,您已经完全正确,而且我希望大多数其他编译器都类似。

【讨论】:

  • 有意义..Vtable 只包含虚函数的地址。但是如何调用派生函数呢? vtable 不包含非虚拟函数的地址 rit.. 我想澄清一下...
猜你喜欢
  • 1970-01-01
  • 2019-11-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 2012-05-19
  • 2012-04-01
  • 1970-01-01
相关资源
最近更新 更多