【问题标题】:Why are pure virtual methods not overridden from a different inheritance branch?为什么不从不同的继承分支覆盖纯虚方法?
【发布时间】:2016-07-06 18:26:58
【问题描述】:

我有这个,可能有点复杂的类层次结构:

class BS {
  public:
    virtual void meth()=0;
};

class BCA : public virtual BS {
};

class BSS : public virtual BS {
};

class BCS : public virtual BCA, public virtual BSS {
};

class BI4 {
  public:
    void meth() {};
};

class BT4 : public virtual BI4, public virtual BSS {
};

class T4 : public virtual BCS, public virtual BT4 {
};

int main() {
  T4 t4;
};

现在的问题是,尽管void meth() 在继承图中可用,尽管这段代码无法编译:

$ g++ -c t.cc -std=c++11
t.cc: In function ‘int main()’:
t.cc:27:6: error: cannot declare variable ‘t4’ to be of abstract type ‘T4’
   T4 t4;
      ^
t.cc:23:7: note:   because the following virtual functions are pure within ‘T4’:
 class T4 : public virtual BCS, public virtual BT4 {
       ^
t.cc:3:18: note:        virtual void BS::meth()
     virtual void meth()=0;
                  ^
t.cc:3:18: note:        virtual void BS::meth()

在我看来,BS 似乎不会通过 BS->BCA->BCS->T4->BT4->BI4 链看到重载的 meth() 方法。
但为什么?方法明显可用,C++使用的C3线性化算法应该可以很清楚的找到。

【问题讨论】:

  • 吹毛求疵:你的意思是“覆盖”而不是“重载”。
  • 多个virtual 继承关系有点矫枉过正。您只需要为基类子对象使用它,否则它们会出现两次或更多次。
  • "little bit complex" o.O 如果名字在任何方面都合理的话,也许不会那么糟糕。
  • "BS->BCA->BCS->T4->BT4->BI4链"先升后降;这不是它的工作原理!
  • 虽然您不能这样做,但您仍然可以委托给 BI4(甚至是模板中的 T)。

标签: c++ c++11 virtual-functions linearization


【解决方案1】:

语言规则不允许。只能通过在派生类中声明具有相同名称和参数的函数来覆盖虚函数。因为BI4 不是从BS 派生的,所以BI4::meth 不能覆盖BS::meth。如果一个类(直接或间接)从BSBI4 继承,那么它会继承两个 函数,称为meth:一个来自BS,仍然是抽象的且未被覆盖,另一个是来自BI4

【讨论】:

    【解决方案2】:

    主要有两个方面:

    • 给定的类只能覆盖其基类的成员函数。
      由于您的 BI4 类没有 BS 作为基类,因此它不能覆盖 BS 中的任何内容。
    • 可以在实现中继承在虚拟基类中定义的纯虚函数,就像在 Java 中一样,但提供该实现的类本身也必须具有该虚拟基类。

    例子:

    struct Base
    {
        virtual void foo() = 0;
    };
    
    #ifdef GOOD
        struct Impl_foo: virtual Base
        {
            void foo() override {}
        };
    #else
        struct Impl_foo
        {
            virtual void foo() {}
        };
    #endif
    
    struct Abstract_derived: virtual Base
    {};
    
    struct Derived
        : Abstract_derived
        , Impl_foo      // Java-like implementation inheritance.
                        // In C++ called "by dominance".
    {};
    
    auto main()
        -> int
    {
        Derived o;
        o.foo();
    }
    

    如果不定义 GOOD 宏符号,此代码将无法编译。

    【讨论】:

      【解决方案3】:

      BI4 不直接或间接继承自BS,因此其方法BI4::meth() 完全不相关,不能覆盖BS::meth()

      您只能覆盖基类中的方法,而不能覆盖“兄弟”或“叔叔”类的方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-06
        • 2018-05-09
        • 2011-08-02
        • 1970-01-01
        相关资源
        最近更新 更多