Reputation: 15351
while trying to analyse in greater depth inheritance mechanism of C++ I stumbled upon the following example:
#include<iostream>
using namespace std;
class Base {
public:
virtual void f(){
cout << "Base.f" << endl;
}
};
class Left : public Base { //NOT VIRTUAL!!!
public:
void g(){
f();
}
};
class Right : public Base{
public:
virtual void f(){
cout << "Right.f" << endl;
}
};
class Bottom : public Left, public Right{
public:
Bottom(int arg){ }
//void f() { }
};
int main(int argc,char **argv)
{
Bottom* b = new Bottom(23);
b->g();
}
It is clear that calling
b->f()
is ambiguous, so there is no unique method f()
on object Bottom. Now, calling
b->g()
works fine and prints
Base.f
Well, as far as I see this:
g()
method, as it is non-virtualg()
method is inherited from Left, so we call this inherited methodg()
in Left tries to call virtual method f()
. According to C++ sepcification, we call f()
method of a dynamic type of our pointer (which is Bottom)BUT Bottom does not have method f()
... at least not a unique one. Why does this program executes Left::Base::f()
rather than Right::Base::f()
or why does it simply not states that call to f()
is ambiguous from Bottom?
Upvotes: 1
Views: 653
Reputation: 6507
The short answer is that (as you noted), Bottom
does not have method f()
, so there is no need in trying to call it.
Bottom
contains the two subobjects Left
and Right
. Each of them inherits from Base
, so Bottom
contains the member functions Left::f()
and Right::f()
, but no Bottom::f()
. Since Bottom does not override Left::f()
(using Right::f()
for example), Base::f()
is the unique final overrider in Left::g()
.
cf. the example in 10.3.9 from the C++03 standard.
Upvotes: 2
Reputation: 208446
Since there is no virtual inheritance there are two copies of the Base
object in your Bottom
object. But if you move up the hierarchy to Left
where g()
is defined, there is a single Base
subobject and that is the one being called. Since it is not overridden in Left
(or Bottom
) it will call the Base
version. Note that Right::f()
only overrides f()
for it's own Base
subobject.
Calling f
directly on Bottom
is ambiguous, as there is no f()
in Bottom
it will try to look in it's bases and will find Left::Base::f
and Right::Base::f
and the compiler does not know which of the two to use.
Upvotes: 1