Non-intuitive RTTI behavior in C++

I just discovered that the Runtime-time Type Information in C++ using Visual C++ 2008 was not behaving like I was expecting in some specific scenarii. One of the side effect I had was that a dynamic_cast was returning NULL instead of the object as it should be.

To understand what is going on, better give you some code than a thousand words ;). Let’s say you have this code:


#include <typeinfo>
#include <iostream>
#include <string>

class A;

void print_real_type(const A * const object);

class A
{
public:
virtual ~A(void) {
std::cout << "calling " << __FUNCTION__ << std::endl;
print_real_type(this);
}

virtual void dummy_function(void) {}
};

class B : public A
{
public:
virtual ~B(void) {
std::cout << "calling " << __FUNCTION__ << std::endl;
print_real_type(this);
}
};

void print_real_type(const A * const object)
{
std::cout << "type of " << object << " : " << typeid(*object).name() << std::endl;
}

int main(void)
{
A * object = new B();
print_real_type(object);
delete object;

return 0;
}

The output will be:

type of 00335FC0 : class B
calling B::~B
type of 00335FC0 : class B
calling A::~A
type of 00335FC0 : class A

When you are in the destructor, the type is never the real type of the object but the same as the type of the current destructor. Also, if you implement the function print_real_type before defining the type A, the RTTI will not work:


#include <typeinfo>
#include <iostream>
#include <string>

class A;

void print_real_type(const A * const object)
{
std::cout << "type of " << object << " : " << typeid(*object).name() << std::endl;
}

class A
{
public:
virtual ~A(void) {
std::cout << "calling " << __FUNCTION__ << std::endl;
print_real_type(this);
}

virtual void dummy_function(void) {}
};

class B : public A
{
public:
virtual ~B(void) {
std::cout << "calling " << __FUNCTION__ << std::endl;
print_real_type(this);
}
};

int main(void)
{
A * object = new B();
print_real_type(object);
delete object;

return 0;
}

Will output:

type of 00335FC0 : class A
calling B::~B
type of 00335FC0 : class A
calling A::~A
type of 00335FC0 : class A

Of course, everything using RTTI will work using those behaviors in those particular scenarii. For example, be careful of the dynamic_cast inside a destructor (this should never be done anyway but sometime you debug the code of other people…) or in a function that is defined before the type being dynamic casted… It will not work as you expect and you might lose like me one hour to find out what is going on ūüėČ

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s