Search code examples
c++static-analysisdynamic-castcross-cast

Checking whether a cross-cast could possibly work?


I know that it's legal to use dynamic_cast to do a "cross-cast" across a class hierarchy. For example, if I have classes that look like this:

  A   B
   \ /
    C

If I have an A* pointer that's pointing at an object of type C, then I can use

A* aPtr = /* ... something that produces a C* ... */
B* bPtr = dynamic_cast<B*>(aPtr);

to get a pointer to the B base object of the C I'm pointing at.

The reason I mention this is that at the time that I write the above code, it's possible that the compiler has not yet seen the definition of C even though it's seen A and B. This means that it's possible that the compiler does not detect any sort of connection between A and B, but it still has to compile the code anyway because it's possible for a class like C to exist and for the dynamic_cast to succeed under some circumstance.

The problem is that this means that I can accidentally cross-cast to an object of the wrong type. Suppose that I have classes that look like this:

A   B    D
 \ /   
  C

Here, D is some random unrelated class. If I try writing something like this:

A* aPtr = /* ... get a C* pointer ... */
D* dPtr = dynamic_cast<D*>(aPtr);

Then this dynamic_cast will always fail at runtime, since there's no possible way to connect A and D. If I'm using D accidentally because I meant to use B, the compiler will give me no indication whatsoever that I have a meaningless cast.

My question is: is there some way that I can get the compiler to warn me that the cast will always fail at runtime? I'd be happy with a language-level solution or some compiler setting for any major compiler that could detect this. If there's an external tool, that's fine as well; I just want to know if it's possible to catch this class of errors.


Solution

  • It's not possible to detect this at compile-time. The class C that introduces the relationship could be found in a dynamically loadable library that hasn't even been written yet, and the compiler can't prove otherwise.

    There may be a few exceptions though. If A has only private constructors (or a private destructor) then the compiler can be certain that there will be no new subclasses that aren't named as friends by A.