Reputation: 1652
The following code does not compile, and gcc -std=c++11
says it is an invalid static cast:
class A { public: virtual ~A() {} };
class B { public: virtual ~B() {} };
class AD : public A { public: virtual ~AD() {} };
class AB : public B, public A {};
class ADB : public B, public AD {};
int main() {
ADB adb;
ADB* ptr = &adb;
AB* cast = static_cast<AB*>(ptr);
return 0;
}
I would like to cast a class of type ADB
to AB
. This feels like it should be safe to do - after all, the memory structure of ADB
is B
followed by AD
, which itself is just A
followed by AD
's own members. Thus it would seem that literally forcing compiler to interpret the pointer ptr
as an AB
would always be defined:
class A { public: virtual ~A() {} };
class B { public: virtual ~B() {} };
class AD : public A { public: virtual ~AD() {} };
class AB : public B, public A {};
class ADB : public B, public AD {};
int main() {
ADB adb;
ADB* ptr = &adb;
AB* cast = reinterpret_cast<AB*>(ptr);
return 0;
}
This does not compile either, resulting in the linker complaining about undefined references
to the vtable and to operator delete(void*)
.
So clearly at some point the vtable pointers are not "syncing up" when casted, in which case I somehow need to cast the individual base class of AD
of ADB
to just the A
of AB
. I'm not exactly sure about that, just guessing. How can I do this or something equivalent to it?
Upvotes: 1
Views: 133
Reputation: 1393
You can only successfully cast between classes which are in the object's inheritance structure. So, you can cast an ADB to an A, a B, or an AD. Your rationalization of similar memory layouts does not apply. While an understanding of the underlying implementation can offer helpful insights into certain "how"s and "why"s (especially when it comes to performance), you should not ever have to consider the underlying implementation to understand (or rationalize) the rules of language features. It works the way it does to help you express higher-level intent.
More importantly, you should never circumvent restrictions built in to the language based on exploited knowledge of the underlying implementation. While there may be occasional valid cases to do so, most of the time, it will result in non-portable code or code that doesn't survive an update of the compiler - failing to compile or breaking mysteriously in production.
Anyway, your assumption about memory layout may be incorrect; defining the virtual destructors is forcing the compiler to inject vtable pointers into the memory layouts of A,B, and AD, so the actual memory layout of an ADB may not be what you think it is.
Upvotes: 1
Reputation: 39896
If you want to cast an AB
, a static_cast could only cast an AB
to a B
or an A
. That's all.
This is the guaranty that offers static_cast
at compilation time: It only allows cast operations that are logically ok, between types that are related.
You could also imagine these static_cast, and they would be ok:
But there is NO path in the inheritance hierarchy between AB and ADB to do what you want. In no way AB and ADB are related types.
Upvotes: 0