C++中虚表的结构是怎样的?

问题描述 投票:0回答:4


例如,我有两个“接口”和类类型:

class IPlugin
{
  public:
    virtual void Load(void) = 0;
    virtual void Free(void) = 0;
};

class IFoo
{
  public:
    virtual void Foo(void) = 0;
};


class Tester: public IPlugin, public IFoo
{
   public:
           Tester() {};
          ~Tester() {};

           virtual void Load()
           {
              // Some code here
           }

           virtual void Free()
           {
              // Some code here
           }

           virtual void Foo(void)
           {
              // Some code here
           }
 };

例如

Tester
类型的实例,vtab 实际上具有什么结构?表达式中的
dynamic_cast
运算符将如何执行(我的意思是
dynamic_cast
运算符如何扫描 vtab 以进行有效的引用类型转换):

Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);  

提前致谢!

c++ vtable
4个回答
19
投票

C++ 中的虚拟表是一个实现细节。下图显示了一种可能的实现方式。

Virtual table diagram

存在该类的两个实例(A 和 B)。每个实例都有两个 vtbl 指针,并且 vtbl 包含指向实际代码的指针。

在您的示例中没有实例数据,但出于说明目的,我假设每个类都包含一些实例数据。

当指向

Tester
的指针转换为指向
IFoo
的指针时,指针将如图所示进行调整。它不是指向实例数据的开头,而是指向实例数据的
IFoo
部分。

巧妙的是,使用

IFoo
指针的调用者对类的
IFoo
部分周围的数据没有任何了解。对于使用
IPlugin
指针的调用者来说也是如此。该指针恰好指向实例数据的开头,该实例数据也由
Tester
指针指向,但只有使用
Tester
指针的调用者知道实例数据的整个布局。

使用

dynamic_cast
需要 RTTI(运行时类型信息),该信息未显示在图表中。 vtbl 将包含附加类型信息,给定一个指向
IFoo
实例的
Tester
指针,允许代码在运行时发现指针所指向的对象的实际类型,并使用它来向下转换指针。


6
投票

对于 Tester 类型的实例,vtab 实际上具有什么结构?

虚拟调度的机制是实现定义的。 C++ 标准不需要 vtable 和 vptr,并且程序员甚至不需要使用 C++ 进行编程,因为您无法访问虚拟表(即使您的编译器实现了此功能);它由编译器生成并添加到您的代码中,就像它在将代码转换为机器代码之前对您的代码做了很多事情一样。


Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);  

这里第二行不需要

dynamic_cast
。以下内容就足够了:

Tester* t = new Tester();
IPlugin* plg = t;                 //upcast          - dynamic_cast not needed
IFoo* f=dynamic_cast<IFoo*>(plg); //horizontal-cast - dynamic_cast needed
向上转型中不需要

dynamic_cast
;仅在向下投射和水平投射时需要它。

Tester* tester1 = dynamic_cast<Tester*>(plg); //downcast - dynamic_cast needed
Tester* tester2 = dynamic_cast<Tester*>(f);   //downcast - dynamic_cast needed

6
投票

ISO/IEC 14882 第二版 2003-10-15 中不存在这样的术语 vptr,虚拟表,所以它完全取决于编译器实现者。

有关 impl 的信息。在微软的 Visual C++ 中: http://www.openrce.org/articles/files/jangrayhood.pdf

关于 impl 的文章。 g++ 中的虚拟表: https://web.archive.org/web/20090123142656/http://phpcompiler.org/articles/virtualinheritance.html


3
投票

虚拟机制(虚拟指针和虚拟表)不是由C++标准定义的。编译器可以按照自己选择的方式实现该机制。它是编译器的实现细节。鉴于此,编译器如何实现虚拟机制的细节是从用户那里抽象出来的。重要的只是虚拟机制预期的行为。

您的情况:

Tester* t = new Tester(); 
IPlugin* plg = dynamic_cast<IPlugin*>(t); 
IFoo* f = dynamic_cast<IFoo*>(plg);   

plg
f
都将指向各自类型的有效对象,因为
t
都是从它们派生的。

当然,这并不能回答您提出的具体问题,而只是想澄清虚拟机制的细节,即编译器的实现细节。

© www.soinside.com 2019 - 2024. All rights reserved.