例如,我有两个“intefaces”和类类型:
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
}
};
vtab实际上具有什么结构,例如Tester
类型?如何dynamic_cast
操作符(我的意思是dynamic_cast
运算符如何在表达式中扫描vtab以获取有效的引用类型转换):
Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);
提前致谢!
答案 0 :(得分:18)
C ++中的虚拟表是一个实现细节。一个可能的实现如下图所示。
存在类(A和B)的两个实例。每个实例都有两个vtbl指针,vtbl包含指向实际代码的指针。
在您的示例中没有实例数据,但出于说明目的,我假设每个类都包含一些实例数据。
当指向Tester
的指针转换为指向IFoo
的指针时,指针会如图所示进行调整。它不是指向实例数据的开头,而是指向实例数据的IFoo
部分。
巧妙的是,使用IFoo
指针的调用者对该类IFoo
部分周围的数据一无所知。对于使用IPlugin
指针的调用者来说,情况也是如此。该指针恰好指向Tester
指针指向的实例数据的开始,但只有使用Tester
指针的调用者才知道实例数据的整个布局。
使用dynamic_cast
需要RTTI(运行时类型信息),这不在图上。 vtbl将包含额外的类型信息,给出IFoo
指向Tester
实例的指针{{1}}允许代码在运行时发现指针指向的实际对象类型并使用它来向下转换指针。
答案 1 :(得分:5)
vtab实际上具有什么结构,例如Tester类型?
虚拟调度的机制是实现定义的。 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
答案 2 :(得分:5)
在 ISO / IEC 14882第二版2003-10-15 中,不存在类似的术语 vptr,虚拟表,因此完全取决于编译器实现者。
有关impl的信息。在microsoft的visual C ++中: http://www.openrce.org/articles/files/jangrayhood.pdf
关于impl的文章。 g ++中的虚拟表: http://phpcompiler.org/articles/virtualinheritance.html
答案 3 :(得分:3)
虚拟机制(虚拟指针和虚拟表)未由C ++标准定义。遗留下来让编译器以自己选择的方式实现机制。它是编译器的实现细节。鉴于此,编译器将如何实现虚拟机制的细节从用户中抽象出来。重要的只是虚拟机制所期望的行为。
在你的情况下:
Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);
plg
&amp; f
两者都会指向各自类型的有效对象,因为t
来自两个类型。
当然,这并不能回答您提出的具体问题,只是想清除虚拟机制的详细信息,作为编译器的实现细节。