Reputation: 9649
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
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
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
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
Reputation: 4641
f() is ambiguous so the compiler does not know which f() to call. Use dynamic_cast as your already suggested.
Upvotes: 0