In a project of mine here I have a class that implements four interfaces:
class A : public B,
public C,
public D,
public E
{
----Implementation Code here----
};
these four interfaces contains only pure virtual functions, none of them compose the diamond problem (so I don’t need to use the virtual keyword) so I spected no problem when doing something like this:
A* var = new A;
((C*)var)->method_from_interface();
Yet something ugly is happening, because the function is jumping around to a different method of the A class, and valgrind complains about an unhandled instruction. However, doing this:
A* var = new A;
(dynamic_cast<C*>(var))->method_from_interface();
works as suspected.
So I’m wondering if this is a G++ bug or some misuse of the language?
edit:
Maybe I’ve simplified too much my problem. I’m receiving the A class as a D* on a function call:
void do_something(provider* p) {
D* iface = p->recoverItemByName("nameThatReturnsClassA");
((B*) iface)->call_method_from_b_iface();
}
Note that I know that in this time the D* is in fact an A*, so casting doing a casting to B* isn’t breaking any rules. I can’t static_cast it, though, as D* and B* have no relation, but I can use reinterpret_cast successfully.
Wrong.
You may know that it’s actually an A*, but the compiler doesn’t, at least at compile time when it’s trying to figure out what code to emit to do the conversion.
A funny thing happens when you inherit from multiple classes with virtual methods. When you convert from the derived class to one of the interface classes, the pointer address changes! The compiler does adjustments to the pointer to make it valid for the pointer type you’ve declared. Try it yourself, start with an
A*pointer and display its value, then cast to aB*,C*, andD*and display those. At most one of the base classes will be the same as theA*, the others will be different.When you use a C-style cast you’re telling the compiler “I don’t care if you can’t do the conversion properly, do it anyway.” It duly treats the
D*as aB*without doing the required fixups, so now the pointer is completely wrong. It isn’t pointing to the class B vtable so the wrong methods get called.A dynamic_cast works because it uses extra information available at run-time; it can trace the pointer to its most-derived
A*and then back down to aB*.