C++ 中虚拟表的结构是什么?

发布于 2024-11-05 02:34:21 字数 901 浏览 1 评论 0原文


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

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);  

提前致谢!

For Example I have two "intefaces" and class type:

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
           }
 };

What structure vtab actually has for instance of type Tester? And how would be dynamic_cast operator act ( I mean how dynamic_cast operator would scan vtab for valid reference type convertion) in expression:

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

Thanks in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

早乙女 2024-11-12 02:34:21

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

虚拟表图

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

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

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

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

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

Virtual tables in C++ is an implementation detail. One possible implementation is shown on the diagram below.

Virtual table diagram

Two instances of the class (A and B) exists. Each instance has two vtbl pointers and the vtbl contains pointers to actual code.

In your example there is no instance data, but I have for illustrative purposes assumed that each class contains some instance data.

When a pointer to Tester is cast to a pointer to IFoo the pointer is adjusted as shown on the diagram. Instead of pointing to the start of the instance data it points to the IFoo part of the instance data.

The neat thing is that a caller using an IFoo pointer doesn't have any knowledge about the data surrounding the IFoo part of the class. The same can be said of for a caller using an IPlugin pointer. This pointer happens to point to the start of the instance data also pointed to by a Tester pointer but only a caller using a Tester pointer knows the entire layout of the instance data.

Using dynamic_cast requires RTTI (Run-Time Type Information) which is not on the diagram. The vtbl will contain additional type information that given a say IFoo pointer to an instance of Tester allows the code at run-time to discover the actual type of object pointed by the pointer and use that to downcast the pointer.

呆萌少年 2024-11-12 02:34:21

对于 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

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

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

What structure vtab actually has for instance of type Tester?

The mechanism of virtual dispatching is implementation-defined. vtable and vptr are not required by the C++ Standard and that knowledge isn't even necessary for programmers to program in C++, because you cannot access the virtual table (even if your compiler implements this); its generated by the compiler and added to your code, like it does lots of things to your code before it converts it into machine code.


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

Here dynamic_cast is not needed in the second line. The following is enough:

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 is not needed in upcast; its needed in downcast and horizontal-cast only.

Tester* tester1 = dynamic_cast<Tester*>(plg); //downcast - dynamic_cast needed
Tester* tester2 = dynamic_cast<Tester*>(f);   //downcast - dynamic_cast needed
眉黛浅 2024-11-12 02:34:21

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

In ISO/IEC 14882 Second edition 2003-10-15 there is not exist such terms like
vptr, virtual table, so it is completely up to compiler implementators.

Info about impl. in microsoft's visual C++:
http://www.openrce.org/articles/files/jangrayhood.pdf

Article about impl. virtual tables in g++:
https://web.archive.org/web/20090123142656/http://phpcompiler.org/articles/virtualinheritance.html

无语# 2024-11-12 02:34:21

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

在您的情况下:

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

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

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

Virtual Mechanism(Virtual Pointer & Virtual Table) is not defined by the C++ standard. It is left out for the compiler to implement the mechanism in its own choosen way. It is an implementation detail of the compiler. Given that, the details of how the compiler will implement the virtual mechanism is abstracted from the user. What should matter is only the beahviors that are expected out of the virtual mechanism.

In your case:

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

plg & f both will point to a valid object of their respective types because t is derives from both of them.

Ofcourse this does not answer the specific question you asked but just wanted to clear the detail on virtual mechanism being a implementation detail of the compilers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文