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!
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.