dynamic_cast question

Started by
11 comments, last by Helter Skelter 18 years, 9 months ago
Anyone know if its possible for a dynamic_cast to return NULL when the object you are casting really is of the type you are casting to? ie class A {} class B : public A {} B b; A* a = (A*)&b B* c = dynamic_cast< B* > ( a ); this should be okay since "a" really is a B object. Sometimes its returning NULL on me, when it shouldn't. Also according to the VS.Net debugger, putting a watch on the "a" variable really does show it to be a B object.
Advertisement
If your class has no virtual functions then calling dynamic_cast on one of its pointers is bad mojo.
If by 'sometimes' you mean with some classes in the heirarchy and not others, you need to figure out what classes actually fail, and see what's different about them.

Dynamic_cast can also fail if RTTI is turned off..
Quote:Original post by SiCrane
If your class has no virtual functions then calling dynamic_cast on one of its pointers is bad mojo.


What-who-how-why? Makes sense, but do you have a reference to back that up?
Quote:Original post by Kuladus
Quote:Original post by SiCrane
If your class has no virtual functions then calling dynamic_cast on one of its pointers is bad mojo.


What-who-how-why? Makes sense, but do you have a reference to back that up?

The C++ Programming Language Special Edition, section 15.4.1:

"A dynamic_cast requires a pointer or a reference to a polymorphic type in order to do a down-cast or a crosscast."

A class must have a vtable in order to successfully call dynamic_cast on it.
Quote:Original post by Kuladus
Quote:Original post by SiCrane
If your class has no virtual functions then calling dynamic_cast on one of its pointers is bad mojo.


What-who-how-why? Makes sense, but do you have a reference to back that up?


Here's a reference: attempting to dynamic_cast from a base without a virtual function to a derived class generates a _compiler error_ using GCC:

class foo {};class bar : public foo {};int main () {	bar b;	foo * f = &b;	dynamic_cast< bar * >( f );}

**** Incremental build of configuration Debug for project test.24 ****make -k all 'Building file: ../main.cc'g++ -O0 -g3 -Wall -c -fmessage-length=0 -omain.o ../main.cc../main.cc: In function `int main()':../main.cc:7: error: cannot dynamic_cast `f' (of type `class foo*') to type `class bar*' (source type is not polymorphic)make: *** [main.o] Error 1make: Target `all' not remade because of errors.Build complete for project test.24


Example provided uses MinGW's GCC 3.4.2, compiled using the Managed Make C++ Project feature of the Eclipse IDE (3.0.2)

That is, the posters example fails to compile on my system. If your class is indeed polymorphic and you are getting a null pointer, it is because (in approximate likelyhood of chance): it is not of the correct type, or you have memory corruption of some sort, or your compiler needs a bugfix, or your CPU is failing (prehaps due to overheat?), or quantum mechanics are interfering with the normal operation of your computer.
What: polymorphic type requirements for valid RTTI.
Who: there is no 'who' unless you talk to you code AND it talks back.
How: dynamic_cast relies on polymorphic types and RTTI.
Why: because that's what the spec says. Doesn't matter if it's logical or if you agree with it.


If you want a real world example of how dynamic_cast works and is actually implemented look at the source code for the G++ (GNU C++ compiler) runtime library. Understanding even ONE implementation of dynamic_cast can give you a great amount of insight into how it works.

[edit: RTTI and polymorphic types were skewed in 'How']
If I had to implement dynamic_cast in a compiler, I'd just CMP the object's vtable pointer to the compiler-known vtable pointer for the type in question, return the object if they match or NULL otherwise. I wouldn't even have to have an extra RTTI switch.

Same restriction: you would have to use it on types that actually have a virtual table.
Let's try a little "accidental" memory stomping experiment.

#include "conio.h"#include "stdio.h"#include "memory.h"class TestA{public:  TestA() { a = 1; }  virtual int GetValue() { return a; }    int a;};class TestB : public TestA{public:	TestB() { a = 2; }	virtual int GetValue() { return 0; }};void main(){	TestA *a1 = new TestA();	TestA *a2 = new TestB();		TestB *b1 = dynamic_cast<TestB*>(a1);	TestB *b2 = dynamic_cast<TestB*>(a2);		memcpy(a1, a2, 4); // copy the vtable pointer but not the data member.		TestB *b3 = dynamic_cast<TestB*>(a1);		printf("B1: 0x%08X\n", b1);	printf("B2: 0x%08X\n", b2);	printf("B3: 0x%08X\n", b3);		printf("A1->GetValue: %i\n", a1->GetValue());	printf("A2->GetValue: %i\n", a2->GetValue());}


Output:

0x000000000x02DA2C800x02DA2C48A1->GetValue: 0A2->GetValue: 0


Ooosp! I just converted a TestA into a TestB.

This is in MSVC 7.1
Quote:Original post by SiCrane
The C++ Programming Language Special Edition, section 15.4.1:

"A dynamic_cast requires a pointer or a reference to a polymorphic type in order to do a down-cast or a crosscast."

A class must have a vtable in order to successfully call dynamic_cast on it.


Thanks for that reference. Almost sounds theological:

Strousup 15:14:1
"Thou needs a type polymorphic to dynamically cast thy way down!"

This topic is closed to new replies.

Advertisement