Ответ 1
Метод Redeclare r как чистый виртуальный в C:
struct C : A, B {
void q(){
r(); // the problem is here.
}
virtual void r()=0;
};
У меня есть гораздо более сложная структура классов, чем эта, но кипящая проблема до ее сути, это описывает мой сценарий: у меня есть два класса: A и B, которые реализуют чистые виртуальные базовые классы, которые имеют общий предок, и затем третий класс C, который компилирует A и B. Наконец, класс шаблона, который заполняет общие методы в чистой виртуальной базе:
struct I {
virtual void r()=0;
};
struct A : I {};
struct B : I {};
struct C : A, B {
void q(){
r(); // the problem is here.
}
};
struct D : C {
virtual void r(){
}
};
C* c = new D;
c->q();
Моя проблема в том, что я не вижу никакого способа заставить C:: q вызвать r().
void C::q(){
r(); // is ambiguous
A::r(); // is pure virtual
B::r(); // also is pure virtual
D::r(); // C doesn't know about D
((D*)this)->r(); // is dubious and requires C to know about D.
}
Как я могу вызвать метод r() из C, чтобы вызвать правильный виртуальный метод?
Извините, я должен был уточнить, что виртуальное наследование нельзя использовать здесь. Я нашел два решения:
struct C : A, B {
virtual void r()=0;
...
ИЛИ
struct C : A, B {
using A::r;
...
Оба кажутся для того, чтобы все проблемы решались для устранения неоднозначности вызова r().
Метод Redeclare r как чистый виртуальный в C:
struct C : A, B {
void q(){
r(); // the problem is here.
}
virtual void r()=0;
};
Попробуйте виртуальное наследование
struct A : virtual I {};
struct B : virtual I {};
Расскажите компилятору, какая часть иерархии следует:
struct C : A, B {
void q(){
A * p = this;
p->r(); // recent GCC compiles this
}
};
Это неоднозначно, потому что компилятор не знает, к какому r()
нужно вызвать, тот, который исходит от A или того, что происходит от B.
Простым способом является запись:
static_cast<A*>(this)->r();
или
static_cast<B*>(this)->r();
Но я думаю, что ни один из них не является ответом, который вы ищете. Вы очищаете ситуацию, наследуя через virtual
интерфейс I:
struct A : virtual I {};
struct B : virtual I {};
Теперь вы можете позвонить
void C::q() { r(); }
как и следовало ожидать. Простое объяснение этого заключается в том, что с помощью виртуального класса C получает только одну "копию" интерфейса I, а не две. Это устраняет ваш код.
Вы не перегружали r() в дочерних структурах, поэтому он по-прежнему является чисто виртуальным. у меня нет реализации.