为什么纯虚拟方法没有从不同的继承分支重写

Why are pure virtual methods not overridden from a different inheritance branch?

本文关键字:继承 分支 重写 虚拟 方法 为什么      更新时间:2023-10-16

我有这个,也许有点复杂的类层次结构:

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线性化算法应该能够非常清楚地找到它。

语言规则不允许这样做。虚拟函数只能由派生类中具有相同名称和参数的函数的声明来覆盖。由于BI4不是从BS派生的,BI4::meth不能覆盖BS::meth。如果一个类(直接或间接)继承自BSBI4,那么它继承了两个称为meth的函数:一个来自BS,仍然是抽象的,没有被覆盖,另一个来自BI4

主要有两个方面:

  • 给定类只能重写其基类中的成员函数。
    由于您的 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宏符号,则此代码无法编译。

BI4不会

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

只能重写基类中的方法,而不能重写"同级"或"叔类"中的方法。