【问题标题】:Why 'virtual' inheritance is not the default behaviour? [duplicate]为什么“虚拟”继承不是默认行为? [复制]
【发布时间】:2014-03-31 19:06:27
【问题描述】:

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

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

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

【问题讨论】:

  • 使用virtual 关键字会造成菱形继承,但这是不受欢迎的。考虑一个银行账户,它是一个“DollarPaymentEndpoint”和一个“YenPaymentEndpoint”,其中每一个都继承自具有“AmountReceived”成员的“PaymentEndpoint”。
  • Why is the virtual keyword needed? 讨论了为什么 virtual 不是自动的。
  • @DavidSchwartz 我的错误。默认情况下具有虚拟继承会创建意外共享并破坏封装。它还可以防止类成为 POD。
  • @RaymondChen:虽然答案非常相似,但我认为其他问题是关于虚拟成员函数的,而这个问题是关于虚拟继承的。
  • 虚拟继承不会避免钻石,它创建钻石。

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    有开销,试试看:

    #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 在那里,人们还希望在某些情况下会使用它,这会产生更多开销 :-) 也就是说,需要一个或多个额外的间接寻址才能通过 Baz* 访问 Foo::aBaz&amp;。如果编译器以某种方式知道引用的最衍生类型,则编译器可能会选择避免这种情况。

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 2020-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-30
      • 2021-03-24
      • 2011-08-20
      相关资源
      最近更新 更多