[英]Does multiple virtual inheritance involve late binding like inheritance of virtual functions?
与继承虚拟功能不同,解析虚拟继承似乎是枯燥无味的,但也许我只是没有创造力(狡猾?)。
虚拟继承是否与虚函数的继承有关? 具体来说,虚拟继承是否会引发后期绑定? 我看不出任何理由。 由于关键字过载,我只是怀疑。
我意识到标准没有指定虚拟继承的实现。 我对大多数非假想的机器都感兴趣,但不完美。
正如虚函数涉及这些成员函数的后期绑定一样,我想你可以说虚拟继承涉及继承数据成员的后期绑定。 每个子类的内存布局可能完全不同,因此如果没有运行时类型信息,则无法解析类似于baseClassInstance->dataMember
的表达式。 因此, virtual
两种使用都需要使用“vtable”来进行特定于类的查找。
请参阅Edsko de Vries的“多重和虚拟继承的内存布局”,了解GNU编译器集群(gcc)如何实现虚拟继承,包括对象布局,后果等。据我所知,其他编译器在关键点上是相似的。
虚拟继承并非没有运行时成本,但是这种成本的原因不是增加灵活性,而是解决模糊性问题。
例如,一个多继承层次结构,其中类C
通过不同的基类继承两次A
类。 对类型C
的对象的非静态方法A::foo
调用现在是不明确的(无论该调用是否为虚拟)。 问题是传递给成员函数的隐式this
指针。 通常,内存中每个子类的位置由继承层次结构唯一确定,但在这种情况下,由于A
在C
包含两次,编译器必须决定如何调整成员函数调用的this
指针 - 它不能做就它自己而言,它会要求你做出决定。
这个决定更复杂,因为我们不仅可以通过C
调用A::foo
,还可以通过C
的基类调用。 这造成了一个两难境地:根据我们用来调用的基类,编译器会以不同的方式调整this
指针,将我们重定向到内存中A
不同位置,具体取决于我们用于调用的指针类型。 事实上,对于每个C
实例, A
在内存中有两个不同的A
实例。
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();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.