sof
sof

Reputation: 9649

Multiple polymorphism in C++

There's the compile error " ' A ' is an ambiguous base of ' C ' " existing on the test diamond multiple inheritance below,

struct A { void f();};
struct B1: A {};
struct B2: A {};
struct C: B1, B2 {};

void g() {A *o = new C;}

It's solved by virtual inheritance below,

struct B1: virtual A {};
struct B2: virtual A {};

Now there's the compile error " no unique final overridder for ' virtual void A::f() ' in ' C ' " existing on another test diamond multiple polymorphism below,

struct A {virtual void f();};
struct B1: virtual A {void f();};
struct B2: virtual A {void f();};
struct C: B1, B2 {};

void g() {
 A *o = new C;
 o->f();
}

And it can't be solved even by dynamic_cast below,

dynamic_cast<B1 *>(o)->f();

@NOTE

dynamic_cast<T *>(obj_ptr) is actually used to perform typesafe downcast, i.e. when the run-time type Tobj of the object that the obj_ptr points to is a subtype of T, it returns obj_ptr itself; otherwise the NULL pointer. It is mistaken being thought of upcasting the subtype Tobj to the supertype T, otherwise performing upcast at run-time directly contradicts the principle of polymorphism.

IMHO, virtual inheritance is succinct enough to solve the first-half problem at compile-time. In contrast, can you present anything to solve the second-half problem at run-time?

@EDIT

Thanks for your pointing out dynamic_cast doesn't do the job. Corrected.

To sovle the 2nd-half problem, it seems to have no choice but implement the overrider on the final subclass of the diamond hierarchy below,

struct C: B1, B2 {
 void f() {B1::f();} //Hardcode to your choice of overrider
};

Upvotes: 2

Views: 377

Answers (4)

Pochi
Pochi

Reputation: 2194

You probably need to virtual-quantify f() in subclasses as well.

struct A {virtual void f();};
struct B1: virtual A {virtual void f();};
struct B2: virtual A {virtual void f();};
struct C: B1, B2 {};

void g() {
 A *o = new C;
 o->f();
}

Upvotes: 0

Kornel Kisielewicz
Kornel Kisielewicz

Reputation: 57615

Your second example is ill-formed, even without the call. A compiler that accepts it is non-standard conforming. This is quite well illustrated in the C++ standard ( C++11/10.3.13 ):

The following example shows a function that does not have a unique final overrider:

struct A { 
  virtual void f(); 
}; 

struct VB1 : virtual A { // note virtual derivation 
  void f(); 
}; 

struct VB2 : virtual A {
  void f(); 
}; 

struct Error : VB1, VB2 { // ill-formed }; 

struct Okay : VB1, VB2 { 
  void f(); 
}; 

Both VB1::f and VB2::f override A::f but there is no overrider of both of them in class Error. This example is therefore ill-formed. Class Okay is well formed, however, because Okay::f is a final overrider.

As you see there is also a solution presented. In the overriden function you can decide which parent function you want to call, or even call both, by using ::.

struct Okay : VB1, VB2 { 
  void f() { 
    VB1::f(); 
    VB2::f(); 
  }
}; 

Upvotes: 2

Dietmar K&#252;hl
Dietmar K&#252;hl

Reputation: 154025

Well, you still don't have a unique override for f(): this needs to be defined in C using e.g.:

struct C: B1, B2 { void f() { this->B1::f(); } };

You can explicitly qualify a function to enforce using this function without dynamic dispatch (this is the only way to call an abstract function when the object is complete constructed and not yet being destroyed).

Upvotes: 2

Damian
Damian

Reputation: 4641

f() is ambiguous so the compiler does not know which f() to call. Use dynamic_cast as your already suggested.

Upvotes: 0

Related Questions