1

When we are doing dynamic cast:

A* x = ...;
B* b = dynamic_cast<B*>(x);

The dynamic_cast will return valid pointer only when:

  1. A is polymorphic, otherwise compilation fails.
  2. B is equivalent to A or is derived from A B should have a relationship with A in inheritance hierarchy (although I am not sure about the strategy), otherwise returns nullptr. This is updated according to the comments.
  3. The RTTI of *x shows that it is an object of class B or a derived class of B, otherwise returns nullptr.

I am considering the case where both condition 1 and condition 3 are met, except condition 2. This can be possible because of memory copy or reinterpret_cast, etc. All following discussions are based on this scenario.

One little example is here: http://ideone.com/tBctgT

Can I say that: If in such situation did C++ allow the dynamic_cast to be successful, it would still be safe to use the pointer returned by dynamic_cast? If so, why C++ standard determines that the validation of condition 2 is mandatory?

In addition, condition 2 is possible to be examined at compile time. Why C++ standard determines to return nullptr at run-time instead of giving compilation error if it is not considered a proper operation?

deltamaster
  • 111
  • 1
  • 5
  • (2) is incorrect. A and B may well be unrelated. x may be of class C that derives from both A and B. – n. m. could be an AI May 25 '14 at 05:31
  • @n.m. Sorry I do not pretty catch your point. I tried in the case where A is unrelated with B, and *x has RTTI type B, dynamic_cast failed at runtime. – deltamaster May 26 '14 at 05:31
  • There was something about class C in my comment, do you have class C in your example? [Demo](http://ideone.com/6CKBaM), – n. m. could be an AI May 26 '14 at 06:39
  • Cool! That is something new for me. Let me think about it. Here is the code that I am trying to run: http://ideone.com/tBctgT. It looks like the compile time type of pointer is examined so the second conversion failed, but I am not sure about the strategy. – deltamaster May 26 '14 at 07:25
  • Your code has undefined behaviour. Reinterpret-cast is only defined in a very narrow set of circumstances which are not applicable to your code. You should never use reinterpret_cast in any chain of reinterpret_casts that does not start and end with the same type. – n. m. could be an AI May 26 '14 at 07:45
  • I know that using reinterpret_cast here is not a good idea, but I just want to get to know more theoretical thing in the design of the language. In this case, content of \*s and \*a are bitwise identical, and certainly the type_info are identical. Based on my current understanding, verification of condition 2 does not introduce additional safety. If \*s is already corrupted, but happen to have the same type_info as \*a, the pointer can still be reinterpret_cast back to type A\*, and the dynamic_cast will be successful. – deltamaster May 26 '14 at 09:12
  • The runtime system should actually check that the source class (known statically) is actually a *public* base class of the actual RTTI class of the casted-from pointer. In a well-behaved program, it must be a base class, but not necessarily public; this additional condition is checked at runtime. This is prescribed by the standard. [Check gcc implementation here](https://github.com/mirrors/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/dyncast.cc). There is no condition 2 in the standard. – n. m. could be an AI May 26 '14 at 10:07

1 Answers1

1

I think an example is the simplest here:

class A { ... };
class B : public A { ... };
class C : public A { ... };

A *x = new C;
B *y = dynamic_cast<B *>(x);

Point 1.

A is a class, it is polymorphic.

Point 2.

The dynamic_cast<>() is allowed at compile time because B derives from A and x is of type A *.

Point 3.

The dynamic_cast<>() returns null because x does not represent an object of type B (or a class that derives from B.) So the code fails at runtime and you get y == nullptr.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • Well, you are talking about the case where condition 1 and 2 are met, but I am interested in the case where condition 1 and 3 are met. I have no question about the behavior in your case. – deltamaster May 26 '14 at 05:23
  • Do you have an example that compiles and condition 2 is not true? If so you can update your question with said example... – Alexis Wilke May 26 '14 at 05:30
  • Okay, I saw your link. After the `reinterpret_cast<>()` the new object is of type S and thus the RTTI matches S definition(s), nothing else. When you say it's of type S, you lose the RTTI of the other (original) types. C++ is based on C which is very much like that too. Types once compiles become quite subjective. (i.e. as far the the assembly code is concerned, it's just a blob of data.) – Alexis Wilke May 26 '14 at 21:39