У меня есть, может быть, немного сложная иерархия классов:
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 ++, должен очень четко его найти.
Есть два основных аспекта:
BI4
класс не имеет BS
как базовый класс, он не может переопределить что-либо из BS
,Пример:
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
, Если класс наследует (прямо или косвенно) от обоих BS
а также BI4
то наследует два функции называются meth
: один из BS
, все еще абстрактный и не переопределенный, и один из BI4
,
BI4
не наследуется от BS
прямо или косвенно, поэтому его метод BI4::meth()
совершенно не связан и не может переопределить BS::meth()
,
Вы можете переопределять методы только из базовых классов, но не из классов «одноуровневых» или «дядя».