Reputation: 75
I'm studying topics related to multiple inheritance now. I came up with the following code, and couldn't totally figure out the mechanism behind it:
struct root
{
virtual void vfunction(){ /* root version */ }
};
struct mid1:public root
{
virtual void vfunction(){ /* mid1 version */ }
};
struct mid2:public root
{
virtual void vfunction(){ /* mid2 version */ }
};
struct inheritMulti:public mid1, public mid2
{
void ambiguityMethod(){
vfunction(); // error: ambiguous
}
void method1(){
mid1& t = *this;
t.vfunction();
}
void method2(){
mid2& t = *this;
t.vfunction();
}
};
The ambiguityMethod
is an error, obviously. However, the function calls in both method1
and method2
confused me. They are virtual function call as well, and t
is actually of type inheritMulti
. So they should call the inheritMulti
version of vfunction
, but since inheritMulti
doesn't have its own version, I don't know what will happen. And it turns out the call in method1
calls the mid1
version, while the call in method2
calls the mid2
version. Is it something undefined and only happened on my compiler? If not, why does it works like this? How does the vtable handle this kind of situation? Thanks!
Thanks for helping in the first place. I have searched about relating topics myself, so yes, I know "diamond problem". But I think my question is different from that. My main concern is whether the behavior of "virtual function call" in method1
and method2
well-defined or undefined by the standard. In compiler, it behaved like what I mentioned above, but is the behavior promised by the standard? If it is well-defined, why does it call the mid1
and 'mid2' version respectively? (The intuitive thought would be calling the inheritMulti
version since the type of t
is actually inheritMulti
) And also, how does most of the compilers handle this situation? It is weird that virtual function call in method1
and method2
call different functions. Thanks again!
Upvotes: 0
Views: 168
Reputation: 1665
void method1(){
mid1& t = *this;
t.vfunction();
}
Here you are calling vfunction
which is not defined in inheritMulti
hence it will search for the nearest definition of vfunction
, and that is present in mid1
. See the hierarchy.
Root->Mid1->inheritMulti
Root->Mid2->inheritMulti
same in the case of
`void method2(){
mid2& t = *this;
t.vfunction();
}
Here also the nearest definition was found in mid2 and hence the output. These calls are not ambiguous because both structures have created there own copy of vfunction
.
inheritMulti
will have two Subobjects named mid1
and mid2
, and each of these subobjects maintain their own vtable pointer. Though you may think that when you do
mid1& t1 = *this;
and mid2& t2 = *this;
both t1 and t2 are same, but try doing this...
bool same = ((void*)t1) == ((void*)t2); // Result false!
Because compiler generates some code behind to adjust the pointer to point the proper object.
Upvotes: 1
Reputation: 1364
Your code is describing "The diamond problem" well known problem in multiple inheritance (for vfunction
). For method1
and method2
everything is ok, because you are making mid1
and mid2
objects from this
and call vfunction
from their namespaces.
Upvotes: 1
Reputation: 26486
The virtual keyword does not play here at all.
when two classes has functions with the same name, and a third class inherits from them both, you need to manually specify on which base class are you refereing when you invoke that function with the scope operator ::
.
void ambiguityMethod(){
mid1::vfunction();
}
or
void ambiguityMethod(){
mid2::vfunction();
}
or
void ambiguityMethod(){
root::vfunction();
}
with t : (warning: weird syntax ahead!)
t.mid1::vfunction();
you can also override this function and call some base class function, thus specifing just once which function are you invoking:
void inheritMulti::vfunction() override {
return mid1::vfunction();
}
the compiler will search for the nearest function with the same signature when calling vfunction
, and will call this function which in its turn - will call mid1
function
Upvotes: 1