Chris Becke
Chris Becke

Reputation: 36141

Ambiguous inheritance of abstract base classes:

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.

Upvotes: 11

Views: 3075

Answers (5)

liorda
liorda

Reputation: 1572

You haven't overloaded r() in the child structs, so it's still pure virtual. i.e have no implementation.

Upvotes: -1

Simone
Simone

Reputation: 11797

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.

Upvotes: 2

T33C
T33C

Reputation: 4429

Try virtual inheritance

struct A : virtual  I {};
struct B : virtual I {};

Upvotes: 3

dennycrane
dennycrane

Reputation: 2331

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
  }
};

Upvotes: 2

Cătălin Pitiș
Cătălin Pitiș

Reputation: 14327

Redeclare method r as pure virtual in C:

struct C : A, B {
  void q(){
    r();              // the problem is here.
  }

  virtual void r()=0;
};

Upvotes: 4

Related Questions