I define 2 classes
class BaseA {
public:
virtual void methodA() = 0;
};
class BaseB {
public:
virtual void methodB(int val) = 0;
};
Child inherits 2 Base Class
class Child : public BaseA, public BaseB {
public:
void methodA() override {
printf("Child A\n");
}
void methodB(int val) override {
printf("Child B %d\n", val);
}
};
Then I write following code.
void callBaseB(void *p) {
BaseB *b = (BaseB *) p;
b->methodB(0);
}
int main() {
auto child = new Child;
callBaseB(child);
return 0;
}
console print
Child A
Why this happened? Why not call method B?
(This is what happend when a Java engineer try to write C++ code)
>Solution :
You should just do this: void callBaseB(BaseB *p) {p->methodB(0);}.
If you want to keep void *p as a parameter, you need to cast it to exactly Child * first. Either:
BaseB *b = (Child *)p;
b->methodB(0);
Or:
Child *b = (Child *)p;
b->methodB(0);
Alternatively, cast to BaseB * before converting to void *. Then casting from void * back to Base * will work.
What happens here is that the BaseB subobject is at non-zero offset inside of Child.
When you convert Child * to BaseB * (either explicitly with a cast, or implicitly, either by assigning pointers or by calling a method of BaseB on the pointer), the compiler automatically offsets the pointer by the required amount, to point to the BaseB subobject.
The offset is determined entirely at compile-time (unless virtual inheritance is involved), based on the two types.
When you obscure the source type using void *, the compiler has no way to determine the correct offset, and doesn’t even try to apply any offset, so you get weird behavior, because the resulting BaseB * doesn’t point to a BaseB instance, but rather to some junk inside of Child.
Even with virtual inheritance, despite the offset being determined at runtime, the calculation depends on the source pointer type being known.