代码之家  ›  专栏  ›  技术社区  ›  Gergely Tomcsányi

多重继承:使用跳过“virtual”关键字并拒绝菱形层次?

  •  1
  • Gergely Tomcsányi  · 技术社区  · 7 年前

    virtual 关键字来解决“钻石问题”,并创建如下类层次结构:

       A
      / \
     /   \
    B     C
     \   /
      \ /
       D
    

    class A { int a; public: A(int a) : a(a) {} };
    class B : public virtual A { int b; public: B(int a, int b) : A(a), b(b) {} };
    class C : public virtual A { int c; public: C(int a, int c) : A(a), c(c) {} };
    class D : public B, public C { public: D(int a, int b, int c) : A(a), B(0, b), C(0, c) {} };
    

    我找不到问题的答案: 为什么我们必须告诉编译器(使用 事实上的 关键字)我们想要创建一个“菱形”类层次结构?为什么编译器不自动生成它? 如果我们不使用 事实上的

    A     A
    |     |
    |     |
    B     C
     \   /
      \ /
       D
    

    是否存在第二层次结构有用且有效的编程情况? 编辑 事实上的

    2 回复  |  直到 7 年前
        1
  •  1
  •   cdhowie    7 年前

    考虑以下情况: A visitor B C 相互独立地实现此接口,并且需要不同的访问行为。

    class A
    {
    public:
        virtual void visit(int) = 0;
    };
    
    class B : virtual private A
    {
    public:
        virtual void visit(int) { }
    };
    
    class C : virtual private A
    {
    public:
        virtual void visit(int) { }
    };
    
    class D : public B, public C { };
    // error: virtual function 'A::visit' has more than one final overrider in 'D'
    

    does not compile .是的 可取且必要 C 子对象。删除本例中的虚拟继承可以进行编译。

        2
  •  0
  •   eerorika    7 年前

    是否存在第二层次结构有用且有效的编程情况?

    假设存在这种自动化,为了让编译器猜测 A 属于 B 也是 C ,并且 B C 都是 D B (这也取决于 C

    有一种方法可以实现这一点:使所有继承都虚拟化。然而,虚拟继承有一些(小但非零)开销,因此这不是一个理想的解决方案。此外,虚拟继承使静态_转换为派生类型成为不可能,因此这种转换将需要动态_转换,而动态_转换需要运行时类型信息,并且有兴趣允许缺乏RTTI支持的有限C++实现。