为什么'虚拟'继承不是默认行为?

时间:2014-02-28 00:49:42

标签: c++ inheritance virtual multiple-inheritance diamond-problem

我理解在从基类派生时使用虚拟关键字的要求,以避免与钻石继承相关的模糊问题。

但是,我的问题是,为什么这不是C ++中导出类时的默认行为,无论钻石问题是否存在或不存在?

在没有钻石继承的情况下使用'virtual'关键字是否有“伤害”?

2 个答案:

答案 0 :(得分:5)

虚拟继承有一个运行时开销:转换指针需要一个仅在运行时已知的调整,而非虚拟继承可以在编译时知道。它也可以使类派生更复杂,因为虚拟基类是由最终派生类初始化的,而不是(必然)直接从它们继承的类。

因此,当您特别想要钻石结构时,您只需要它;必须记住指定非虚拟继承以避免隐藏的开销是一件痛苦的事。 C ++通常遵循不应该为不需要的功能付费的原则。

答案 1 :(得分:4)

有一个开销,试试吧:

#include <iostream>

struct Foo {
    int a;
};

struct Bar : Foo {
    int b;
};

struct Baz : virtual Foo {
    int b;
};

int main() {
    std::cout << sizeof(Foo) << " ";
    std::cout << sizeof(Bar) << " ";
    std::cout << sizeof(Baz) << "\n";
}

在我的实施中,我得到4 8 16。虚拟继承需要vptr或等效机制,因为类Baz不知道Foo基类子对象相对于Baz基类子对象的偏移量。这取决于派生程度最高的类型是否也通过另一条路由继承Foo

由于vptr在那里,人们也期望在某些情况下会使用它,这是更多的开销:-)也就是说,为了通过{访问Foo::a,需要一个或多个额外的间接指令。 {1}}或Baz*。如果它以某种方式知道参考文献的派生类型最多,编译器可能会选择避免这种情况。