1

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?

15
  • Being derived from the same types does not make them anything but distantly related, not enough for static cast. Commented Jul 27, 2014 at 17:20
  • @StephaneRolland I know. I didn't say it did... Commented Jul 27, 2014 at 17:21
  • Basically, don't do this. This looks like an XY problem. Tell us what you actually want to accomplish, and maybe we can tell you a better way. Commented Jul 27, 2014 at 17:22
  • @Brian well, I was trying to abstract the problem, in essence I'm making a class which carries some data and a templated type T. In order to avoid overhead, I'd be nice to store a struct { meta m; T t; }, the pointer for which which would be contained mytype<T>. But in order to allow casting from mytype<T> to mytype<TBase>, I am instead storing a pointer to a struct stored : public meta, public T, in hopes of accomplishing what's in my question. Commented Jul 27, 2014 at 17:28
  • @StephaneRolland I apologize for being unclear. My what I meant to say is cast a class of type ADB to AB, but I wanted to convey the structure of the types in memory. Commented Jul 27, 2014 at 17:29

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Ah, ok, so it's the virtual destructors then! That's the explanation I was looking for. Let me test that that's actually the case.
Just tested it by removing them, and now it compiles fine! Obviously, without the virtual destructors it can only use nontrivial destruction, and forcing the reinterpret_cast is nonstandard anyway (because it assumes the memory layout is as I described it above, which it doesn't have to be), but at least it all makes sense now, thanks.
0

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:

  • an A in AD
  • a B or an A in AB
  • a B or an AD in ADB
  • an A in ADB

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.

3 Comments

Why aren't they related? How is ADB not just AB with AD's vtable pointer and members appended to it?
class AB : public B, public A {}; class AB is only related to B and A. That's why it's unrelated to ADB.
OK, I understand why it doesn't work according to the standard now, thanks. But do you agree that at the bit level, there doesn't seem to be a problem with the cast? That's what I'm not understanding - what's wrong with the reinterpret_cast?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.