4

我理解从基类派生时使用 virtual 关键字的要求,以避免与菱形继承相关的歧义问题。

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

在不存在钻石继承的情况下使用“虚拟”关键字是否有任何“危害”?

4

2 回答 2

6

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

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

于 2014-02-28T00:59:25.953 回答
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通过 aBaz*或访问Baz&。如果编译器以某种方式知道引用的最派生类型,则编译器可能会选择避免这种情况。

于 2014-02-28T00:55:49.893 回答