I have a far more complicated class structure than this, but boiling the problem down to its essence, this describes my scenario: I have two classes, A & B, that implement pure virtual base classes that share a common ancestor, and then a third class C that com-posits A & B. Finally, a template class that fills in the common methods in the pure virtual base:
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();
My problem is, I can't see any way to get C::q to call 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.
}
How can I call the r() method from C so that the correct virtual method is called?
Sorry, I should have clarified that virtual inheritance can't be used here. I have found two solutions:
struct C : A, B {
  virtual void r()=0;
  ...
OR
struct C : A, B {
   using A::r;
   ...
Both appear to disambiguate the call to r() sufficiently for everything to resolve.
Redeclare method r as pure virtual in C:
struct C : A, B {
  void q(){
    r();              // the problem is here.
  }
  virtual void r()=0;
};
                        Try virtual inheritance
struct A : virtual  I {};
struct B : virtual I {};
                        Tell the compiler which part of the hierarchy to follow:
struct C : A, B {
  void q(){
    A * p = this;
    p->r();              // recent GCC compiles this
  }
};
                        It's ambiguous because the compiler doesn't know which r() to call, the one coming from A or the one coming from B.
The easy way is to write:
static_cast<A*>(this)->r();
or
static_cast<B*>(this)->r();
But I think that none of this is the answer you're looking for. You clean up the situation by inheriting through virtual the interface I:
struct A : virtual I {};
struct B : virtual I {};
Now, you can call
void C::q() { r(); }
as you would expect. The simple explanation of this is that, by using virtual, class C gets only one "copy" of the interface I, not two. This disambiguates your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With