views:

808

answers:

6
+1  Q: 

dynamic_cast fails

I have a base class and a derived class. Each class has an .h file and a .cpp file.

I am doing dynamic_cast of the base class object to the derived class in the following code:

h files:

class Base
{
  public:
    Base();
    virtual ~Base();
};

class Derived : public Base
{
  public:
    Derived(){};
    void foo();
};

class Another
{
  public:
    Another(){};
    void bar(Base* pointerToBaseObject);
};

cpp files:

Base::Base()
{
    //do something....
}
Base::~Base()
{
    //do something....
}
void Derived::foo()
{
    Another a;
    a.bar(this);
}
void Another::bar(Base* pointerToBaseObject)
{
    dynamic_cast<Derived*>(pointerToBaseObject)
}

From some strange reason, the casting fails (returns NULL). However, the casting succeeds if I move the implementation of Derived class's constructor from .h to the .cpp file.

What can cause it?

The compiler is gcc 3.1, on Linux-SUSE. BTW, I see this behavior only on this platform, and the same code works fine in Visual Studio.

+5  A: 

Do you have any virtual function in Base? It won't work otherwise. If nothing else, make its dtor virtual.

Don't know whether it was already asked by the other guy that deleted his answer, but i believe it was something different: Are you doing the dynamic_cast from the bases' constructor? If so, that won't work. The compiler will think that the Base is the most derived type, similar to when you call a virtual function and it ends up calling the version of the Base.

Johannes Schaub - litb
I do have virtual functions in Base.
Igor Oks
+1  A: 

The code, as posted, shouldn't fail, provided you have a virtual function in the base class (as litb pointed out).

But I believe every current compiler generates a "Base class is not polymorphic" kind of error if you hadn't, so that probably won't be the problem.

The only thing I can think of is that due to some weird bug everything gets inlined and no vtable gets generated. But if you put the constructor in the C++ file, the compiler decides not to inline everything, triggering the creation of a vtable, causing your cast to work.

But this is very wild guesswork, and I don't think any compiler would have such a mistake in it (?)

If you want a definite answer, post more code. And the compiler / platform used.

EDIT: Seeing the updated code

I think you should at least derive Derived from Base ;) (I suppose that's a typo)

But after seeing the code, the only thing I can think of is that gcc (wrongly) inlines everything and doesn't generate a vtable for Derived. For what it's worth, this runs fine compiled with gcc 4.0

3.1 is over 7 years old by now... if there's any possibility to upgrade I'd go for it.

Pieter
+3  A: 

Make the destructor virtual, and place it (or at least one virtual method) in the .cpp file.

Some compilers (read: gcc) look for the first-encountered non-inline virtual method body and use it to decide where to put the virtual method table. If you don't have any virtual methods with bodies in a .cpp file, the virtual method table is not created.

You must have at least one virtual method for dynamic_cast to work. Dynamic cast uses the table to figure out type information, and no table is created if there are no virtual methods.

If you have a class that you expect to be subclassed and it has a destructor or if the class has any instance variables that are classes with destructors, then you'll really want to make your destructor virtual (even if it has an empty body). Otherwise the cleanup you expect won't happen for subclass instances.

Mr Fooz
A: 

Are you doing this in Visual C++? I think you use to have to enable runtime type information (RTTI) in the compiler setting for this to work.

Please don't flame me if I've got this wrong. It's been a while since I used C++!!!

Sean
A: 

In looking at your code, I don't see any inheritance. Did you forget to do that? Derived isn't derived from anything.

plinth
A: 

In the code you have posted Derived is not derived from Base.

Edit: FYI, modified code works fine with g++ 3.4.5

anon