C++ 中虚拟表的结构是什么?
例如,我有两个“接口”和类类型:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
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.
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 toIFoo
the pointer is adjusted as shown on the diagram. Instead of pointing to the start of the instance data it points to theIFoo
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 theIFoo
part of the class. The same can be said of for a caller using anIPlugin
pointer. This pointer happens to point to the start of the instance data also pointed to by aTester
pointer but only a caller using aTester
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 sayIFoo
pointer to an instance ofTester
allows the code at run-time to discover the actual type of object pointed by the pointer and use that to downcast the pointer.虚拟调度的机制是实现定义的。 C++ 标准不需要 vtable 和 vptr,并且程序员甚至不需要使用 C++ 进行编程,因为您无法访问虚拟表(即使您的编译器实现了此功能);它由编译器生成并添加到您的代码中,就像它在将代码转换为机器代码之前对您的代码做了很多事情一样。
这里第二行不需要
dynamic_cast
。以下内容就足够了:upcast 中不需要
dynamic_cast
;仅在向下投射和水平投射时需要它。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.
Here
dynamic_cast
is not needed in the second line. The following is enough:dynamic_cast
is not needed in upcast; its needed in downcast and horizontal-cast only.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
虚拟机制(虚拟指针和虚拟表)不是由 C++ 标准定义的。编译器可以按照自己选择的方式实现该机制。它是编译器的实现细节。鉴于此,编译器如何实现虚拟机制的细节是从用户那里抽象出来的。重要的只是虚拟机制预期的行为。
在您的情况下:
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:
plg
&f
both will point to a valid object of their respective types becauset
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.