Почему GCC выдает мне ошибку: нет единственного окончательного переопределения?

В приведенном ниже коде я получаю следующее предупреждение и ошибку:

test.cpp:15: warning: direct base 'B' inaccessible in 'D' due to ambiguity
test.cpp:15: error: no unique final overrider for 'virtual void A::f()' in 'D'

Но если я уберу виртуальное наследование B из A (т.е. struct B : public A), Я получаю только предупреждение, без ошибок.

struct A
{
virtual void f() = 0;
};

struct B : public virtual A
{
void f() {}
};

class C : public B
{};

struct D : public C, virtual B
{};

int main()
{
return 0;
}

Зачем? Это страшный бриллиант?

4

Решение

Это потому что C наследует не виртуальным образом от B в то время как D наследует виртуально от B, Это дает вам B два раза, включая два f(),

Попробуйте виртуальное наследование B в C,

Обновление: так почему это работает, когда вы удаляете виртуальное наследование в B от A? Потому что это меняет «окончательный переопределение». Без виртуального входа B от A И в C от B у тебя есть A два раза: один раз в C (с окончательным переопределением f() в B) и один раз в виртуал B в D (с окончательным переопределением f() в B). Если вы добавите обратно виртуальное наследование в B в A, A будет присутствовать только один раз, и будет два финальных переопределения, конкурирующих за реализацию чистого f() от A, оба в Bоднажды из C и один раз из виртуального B,

В качестве обходного пути вы можете добавить using до D, то есть using C::f; или же using B::f,

См. C ++ 10.3 / 2

3

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

Давайте посмотрим на определение «окончательного переопределения» из 10.3[class.virtual]/2

Виртуальная функция-член C::vf объекта класса S является окончательным переопределением, если самый производный класс которого S подобъект базового класса (если есть) объявляет или наследует другую функцию-член, которая переопределяет vf,

В производном классе, если виртуальная функция-член подобъекта базового класса имеет более одного окончательного переопределения, программа некорректна.

При виртуальном наследовании от A существует только один подобъект базового класса типа A, а его виртуальная функция-член f () имеет более одного окончательного переопределения (по одному в каждом подобъекте типа B)

Без виртуального наследования от A есть два разных подобъекта базового класса типа A, и у каждого из их виртуальных функций-членов f () есть свой конечный переопределитель (по одному в каждом подобъекте B)

2

Виртуальные базовые подобъекты являются «общими» для всех базовых подобъектов в целостном объекте. Поскольку A является общим для D :: C :: B и D :: B, он не может сказать, какой объект B должен иметь его f() называется переопределением для A::f().

Рассматривать:

#include <iostream>

struct A {
virtual void f() = 0;
virtual ~A() {}
};

struct B : virtual A
{
void f() { std::cout << "B\n"; }
};

struct C : virtual A
{
void f() { std::cout << "C\n"; }
};

struct D : C, B {};

int main() {
D d;
A *a = dynamic_cast<A*>(&d); // single shared A between B and C
a->f(); // Should B::f() be called, or C::f()?
}

Базовые подобъекты B и C в D совместно используют один и тот же базовый подобъект A. Когда мы вызываем A :: f (), выполняется виртуальный поиск для переопределяющей функции. Но и B, и C пытаются переопределить это, так какой из них «выигрывает»? Есть ли x->f() печатать «B» или «C»? Ответ заключается в том, что программа, которая попадает в ситуацию, является плохо сформированной.

Когда мы исключаем совместное использование, заставляя B и C наследовать не виртуально, то у каждого отдельного базового подобъекта A свои функции переопределяются уникальными базовыми классами:

#include <iostream>

struct A {
virtual void f() = 0;
virtual ~A() {}
};

struct B : A
{
void f() { std::cout << "B\n"; }
};

struct C : A
{
void f() { std::cout << "C\n"; }
};

struct D : C, B {};

int main() {
D d;
// two different A objects
A *a1 = static_cast<A*>(static_cast<B*>(&d));
A *a2 =  static_cast<A*>(static_cast<C*>(&d));
a1->f();
a2->f();
}
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector