Почему чисто виртуальные методы не переопределяются из другой ветви наследования?

У меня есть, может быть, немного сложная иерархия классов:

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 как-то не увидит перегруженного meth() метод через цепочку BS-> BCA-> BCS-> T4-> BT4-> BI4.
Но почему? Метод доступен, алгоритм линеаризации C3, используемый C ++, должен очень четко его найти.

1

Решение

Есть два основных аспекта:

  • Данный класс может переопределять функции-члены только из своих базовых классов.
    Так как ваш 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 символ макроса, этот код не компилируется.

2

Другие решения

Правила языка не позволяют этого. Виртуальная функция может быть переопределена только объявлением функции с тем же именем и параметрами в производном классе. поскольку BI4 не выводится из BS, BI4::meth не может переопределить BS::meth, Если класс наследует (прямо или косвенно) от обоих BS а также BI4то наследует два функции называются meth: один из BS, все еще абстрактный и не переопределенный, и один из BI4,

5

BI4 не наследуется от BS прямо или косвенно, поэтому его метод BI4::meth() совершенно не связан и не может переопределить BS::meth(),

Вы можете переопределять методы только из базовых классов, но не из классов «одноуровневых» или «дядя».

2
По вопросам рекламы [email protected]