多个虚拟继承是否涉及后期绑定,如虚函数的继承?

时间:2014-07-01 07:08:35

标签: c++ multiple-inheritance virtual-functions virtual-inheritance

与继承虚拟功能不同,解析虚拟继承看起来很干脆但也许我不够有创意(狡猾?)。

虚拟继承是否与虚函数的继承有关?具体来说,虚拟继承是否会引发后期绑定?我看不出任何理由。由于关键字过载,我只是怀疑。

我意识到标准没有指定虚拟继承的实现。我对大多数非假想的机器都感兴趣,但不完美。

2 个答案:

答案 0 :(得分:5)

正如虚函数涉及这些成员函数的后期绑定一样,我想你可以说虚拟继承涉及继承数据成员的后期绑定。每个子类的内存布局可能有很大不同,因此如果没有运行时类型信息,则无法解析baseClassInstance->dataMember这样的表达式。因此virtual的两种用法都需要使用" vtables"用于特定于类的查找。

请参阅"Memory Layout for Multiple and Virtual Inheritance", by Edsko de Vries,了解GNU编译器集群(gcc)如何实现虚拟继承,包括对象布局,后果等。据我所知,其他编译器在关键点。

答案 1 :(得分:1)

虚拟继承并非没有运行时成本,但是这种成本的原因不是增加灵活性,而是解决模糊性。

以多继承层次结构为例,其中类C通过不同的基类继承了类A两次。对类型为A::foo的对象的非静态方法C的调用现在是不明确的(无论该调用是否为虚拟调用)。问题是传递给成员函数的隐式this指针。通常,内存中每个子类的位置由继承层次结构唯一确定,但在这种情况下,由于A中包含两次C,编译器必须决定如何调整this成员函数调用的指针 - 它不能单独执行,因此它会要求您决定。

此决定更加复杂,因为我们不仅可以通过A::foo调用C,还可以通过C的基类调用this。这造成了两难:根据我们用于调用的基类,编译器将以不同的方式调整A指针,将我们重定向到内存中A的不同位置,具体取决于我们指针类型用于通话。实际上,对于C的每个实例,我们在内存中有两个不同的class A { public: void foo(); [...] }; class B1 : public A {}; class B2 : public A {}; class C : public B1, public B2 {}; C c; B1* b1 = &c; B2* b2 = &c; //assume foo() changes some internal state of A b1->foo(); //the state change of the previous line is not visible //to the next call - they operate on distinct instances of A b2->foo(); 实例。

virtual

A继承引入了一个额外的间接层来解决这种歧义。不是在编译时确定A::foo相对于其子类的位置,而是执行运行时查找。这允许编译器传递相同的内存位置调用C,无论通过哪个派生类进行调用。对于A的每个实例,我们现在只在内存中有一个class B1 : virtual public A {}; class B2 : virtual public A {}; [...] C c; B1* b1 = &c; B2* b2 = &c; //both calls will now operate on the same instance of A //state changes performed by the one will be observed by the other b1->foo(); b2->foo(); 实例。

{{1}}