【问题标题】:Diamond inheritance and pure virtual functions钻石继承和纯虚函数
【发布时间】:2010-10-02 05:43:34
【问题描述】:

想象一下标准的钻石继承。 A 类定义了纯虚函数 fx,B 类定义了 fx 的实现,C 类和 D 类对 fx 没有任何作用。当尝试在 D 类的实例上调用 fx 时,您将收到“模糊函数调用”错误,尽管 fx 只有一种实现。这可以通过 B 和 C 以虚拟方式从 A 继承来解决。它是解决问题的正确解决方案吗?虚继承究竟是如何处理虚函数表的合并的?

A--->B--->D

\--->C------^

【问题讨论】:

    标签: c++ function inheritance virtual


    【解决方案1】:

    ... 注意,Herb Sutter 写了 3 篇关于多重继承的优秀文章 (1) here(2) here(3) here。他在 guru-of-the-week here 中写了一大堆有用的文章。强烈推荐...

    首先,我不确定你的层次结构是否正确。我认为它是这样的:

    struct A {
        virtual void F() = 0;
    };
    
    struct B : A { void F() { } };
    struct C : A { };
    struct D : B, C { };
    

    嗯,D 是抽象的,因为 D 类型的对象中有两个 A 子对象:一个由 B 通过 B 的格子具体化,一个在经过的格子中仍然是抽象的C。我认为你有一个指向D 的指针并尝试调用F。是的,产生了歧义,因为编译器在两个单独的格中找到了两个函数F

    D -> B::F
    D -> C -> A::F
    

    看起来像这样:

        F()   F()
         A     A
         |     |
     F() B     C
          \   /
            D 
    

    您可以通过虚拟地从 A 派生来正式解决这种情况:

    struct B : virtual A { void F() { } };
    struct C : virtual A { };
    struct D : B, C { };
    

    那么你就有了这种情况,称为菱形继承:

           F()  
            A
          /   \
     F() B     C
          \   /
            D 
    

    然后进行查找,发现有B::F 覆盖A::F。虽然A::F 仍然可以通过D::C::A 到达,但这不再是一个歧义,因为A 是继承虚拟的。

    这是否是您特定问题的正确解决方案 - 当然不确定。通常有比从类派生虚拟更好的方法。关于合并虚函数表的问题 - 这完全取决于实现。据我所知,GCC 将在D 的虚拟表中保留一个指向 A 实例的指针,如果我们派生虚拟。

    【讨论】:

    • 谢谢。这是我问过的。如果功能依赖于编译器实现,那就没办法了。
    • 每个编译器的行为都是相同的——编译器实现它的方式不同。只要您不依赖依赖于实现的对象的特定布局(例如 sizeof 值),您就可以相信编译器的行为彼此相似。
    • 好吧,我问的更准确一点:如果有菱形虚继承,并且A和B都定义了一个函数,而C中没有,我可以通过D访问该函数吗?那会是哪一个,A中定义的那个还是B中定义的那个?所有编译器的行为是否一致?
    • B 被调用,因为它覆盖了 A 中的函数 F。只要 C 中没有函数 F(这会引入歧义 - A::F 没有唯一的最终覆盖器),你可以在 D 对象上调用它,然后在 B 中调用它,当然对于所有符合标准的编译器。
    【解决方案2】:

    这是一个正确解决问题的方法吗?

    “钻石”继承是有问题的,解决方案的正确解释需要一点解释。我建议你阅读 Meyers 的 Effective C++ 的以下章节:

    • 第 26 项,防范潜在的歧义
    • 第 43 条,明智地使用多重继承

    【讨论】:

      猜你喜欢
      • 2012-04-19
      • 2012-08-06
      • 2020-01-01
      • 1970-01-01
      • 2011-11-18
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 2015-08-07
      相关资源
      最近更新 更多