Solved

dynamic_cast code crashes on vc++

Posted on 2003-11-11
3
535 Views
Last Modified: 2010-05-18
in following code dynamic_cast is crashing

Atom *a=(*p)["sn"];
    if (!a)
    throw ProtocolEx(BAD_PACKET);
  IntAtom *ia=dynamic_cast<IntAtom *>(a);
 
whats the reason?
0
Comment
Question by:nrusinh
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 17

Accepted Solution

by:
rstaveley earned 50 total points
ID: 9721756
The dynamic_cast<> does a run-time check to ensure that your instance of Atom is indeed an instance of an IntAtom. If a is not an instance of IntAtom, your ia pointer will point to 0.

It looks like you are doing a "downcast", which is OK provided that IntAtom is derived from Atom and the Atom pointer is actually pointing to an instance of an IntAtom. If it isn't, your dynamic_cast<> will fail.

This is OK for a downcast:

  Atom *a = new IntAtom;              
  IntAtom* ia = dynamic_cast<IntAtom*>(a);    

This isn't OK:

  Atom *a = new Atom;              
  IntAtom* ia = dynamic_cast<IntAtom*>(a);    

You'll need to do a reinterpret_cast<> is you want to be evil and treat an instance of Atom as you would an instance of IntAtom.

This is evil, but will work if you know that the bit patterns are the same for Atom and IntAtom:

  Atom *a = new Atom;              
  IntAtom* ia = reinterpret_cast<IntAtom*>(a);  // Evil downcast
0
 

Author Comment

by:nrusinh
ID: 9728557
Can you further tell me what does reinterpret_cast do and when it should be used.

thanks in advance.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9730664
A class instance consists of a chunk of memory for its data and, if there are virtual functions, a pointer to its virtual method table (VMT). When there are virtual functions, the class is known as "polymorphic", and only polymorphic classes can use dynamic casts, reinterpret casts tell the compiler to treat the pointer to treat the instance as if it was and instance of whatever you want to reintrepret the pointer as. When a programmer uses a reinterpret_cast, he says, "I know what I'm doing... I can treat this chuk of memeory as an instance of X."

A non-polymorphic class can generally quite safely be reinterpret downcasted, if you are only going to access data members from the base class.

In the following example a derived class has the same data members as the base class, which means that an instance of a derived class is laid out in memory no differently from the base class and for that reason, the oh-so-evil reinterpret_cast may be used with confidence:
--------8<--------
#include <iostream>

// Base class
class Base {
int x;
public: Base(int x = 0) : x(x) {}
        void setX(int);
        int getX() const;
};

// Class function implementation
void Base::setX(int x)
{
        Base::x = x;
}

int Base::getX() const
{
        return x;
}

// Derived class
class Derived : public Base {

        // No additional data

public: void print() const;
};

// Derived function implementation
void Derived::print() const
{
        std::cout << "This class has value " << getX() << '\n';
}

int main()
{
        // Create an instance of a Base class
        Base *base = new Base(123);

#if 0 /* This won't compile because Base isn't polymorphic */

        // Use a dynamic cast to downcast it to a Derived class
        Derived *derived_d = dynamic_cast<Derived*>(base);
        if (derived_d) {
                std::cout << "We derived using a dynamic downcast\n";
                derived_d->print();
        }
        else
                std::cout << "Unable to treat it as Derived using a dynamic downcast\n";

#endif

#if 1 /* This compiles, because reinterpret_cast doesn't require Base to be polymorphic */

        // Use a reinterpret cast to downcast it to a Derived class
        Derived *derived_r = reinterpret_cast<Derived*>(base);
        if (derived_r) {
                std::cout << "We derived using a reinterpret downcast\n";
                derived_r->print();
        }
        else
                std::cout << "Unable to treat it as Derived using a reinterpret downcast\n";

#endif

}
--------8<--------

If a derived class adds data members to a base class, we know that the members declared by the base class appear first and thus a dynamic downcast on an instance of a base class works OK for the base class members:
--------8<--------
#include <iostream>

// Base class
class Base {
int x;
public: Base(int x = 0) : x(x) {}
        void setX(int);
        int getX() const;
};

// Class function implementation
void Base::setX(int x)
{
        Base::x = x;
}

int Base::getX() const
{
        return x;
}

// Derived class
class Derived : public Base {

        // Here we are adding data!
        int y;

public: Derived(int y = 0,int x = 0) : Base(x),y(y) {}
        void print() const;
};

// Derived function implementation
void Derived::print() const
{
        std::cout << "This class has X value " << getX() << " and Y value " << y << '\n';
}

int main()
{
        // Create an instance of a Base class
        Base *base = new Base(123);

        // Use a reinterpret cast to downcast it to a Derived class
        Derived *derived_r = reinterpret_cast<Derived*>(base);
        if (derived_r) {
                std::cout << "We derived using a reinterpret downcast\n";
                derived_r->print();
        }
        else
                std::cout << "Unable to treat it as Derived using a reinterpret downcast\n";
}
--------8<--------
You may find that you got an access error in your implementation, when you ran this code (I happened to get away with it with mine), because the assumed location of y in print() is in unallocated memory. We instantiated a Base class and then got the compiler to treat our pointer as if it was pointing to a derived class. Accessing the x value was reliable, but what you see with y is undefined. If you can't get any output in your implementation, remove the y from your print() function, and you should find it works OK for x.

Let's look at dynamic_cast and reinterpret_cast with a polymorphic class. By making the getX() member virtual, the class becomes polymorphic:
--------8<--------
#include <iostream>

// Base class
class Base {
int x;
public: Base(int x = 0) : x(x) {}
        void setX(int);
        virtual int getX() const; // <- Look I've made it polymorphic!
};

// Class function implementation
void Base::setX(int x)
{
        Base::x = x;
}

int Base::getX() const
{
        return x;
}

// Derived class
class Derived : public Base {

        // Here we are adding data!
        int y;

public: Derived(int y = 0,int x = 0) : Base(x),y(y) {}
        void print() const;
        int getX() const;       // <- Override
};

// An override of the getX function - lets double x to make it look different
int Derived::getX() const
{
        return Base::getX()*2;
}

// Derived function implementation
void Derived::print() const
{
        std::cout << "This class has X value " << getX() << " and Y value " << y << '\n';
}

int main()
{
        // Create an instance of a Base class
        Base *base = new Base(123);

/* This should compile because Base is polymorphic - however I wouldn't expect the dynamic downcast cast to work at run-time, because the VMT doesn't match the VMT required for an instance of Derived */

        // Use a dynamic cast to downcast it to a Derived class
        Derived *derived_d = dynamic_cast<Derived*>(base);
        if (derived_d) {
                std::cout << "We derived using a dynamic downcast\n";
                derived_d->print();
        }
        else
                std::cout << "Unable to treat it as Derived using a dynamic downcast\n";

        // Use a reinterpret cast to downcast it to a Derived class
        Derived *derived_r = reinterpret_cast<Derived*>(base);
        if (derived_r) {
                std::cout << "We derived using a reinterpret downcast\n";
                derived_r->print();
        }
        else
                std::cout << "Unable to treat it as Derived using a reinterpret downcast\n";
}
--------8<--------
Notice that the getX() used by the print() was the getX() from Base? It was taken from the VMT.

Let's think of a reasonable use of reinterpret_cast. Let's say you had some legacy function which you needed to use to pass an instance of your class (e.g. TCP/IP socket code or a Windows call-back) and you lost the type of the class in the process (it now appeared as a void*), but the programmer knew that the class was an instance of a polymorphic class derived from Base. The programmer could use the evil reinterpret_cast to treat the pointer as a pointer to an instance of polymorphic class Base and use a dynamic_cast to get the appropriate run-time cast:
--------8<--------
#include <iostream>

// Base class
class Base {
int x;
public: Base(int x = 0) : x(x) {}
        void setX(int);
        virtual int getX() const;
        void print() const; /* Not a virtual function - probably a poor design decision */
        virtual void printv() const; /* A virtual function - probably a better design decision */
};

// Class function implementation
void Base::setX(int x)
{
        Base::x = x;
}

int Base::getX() const
{
        return x;
}

void Base::print() const
{
        std::cout << "Base non-virtual print: This class has X value " << getX() << '\n';
}

void Base::printv() const
{
        std::cout << "Base virtual print: This class has X value " << getX() << '\n';
}

// Derived class
class Derived : public Base {

        // Here we are adding data!
        int y;

public: Derived(int y = 0,int x = 0) : Base(x),y(y) {}
        void print() const;
        void printv() const;    //  Override
        int getX() const;       //  Override
};

// An override of the getX function - lets double x to make it look different
int Derived::getX() const
{
        return Base::getX()*2;
}

// Derived function implementation
void Derived::print() const
{
        std::cout << "Derived non-virtual print: This class has X value " << getX() << " and Y value " << y << '\n';
}

void Derived::printv() const
{
        std::cout << "Derived virtual print: This class has X value " << getX() << " and Y value " << y << '\n';
}

void handle_void_ptr(void*);

int main()
{

/* Consider we are using some legacy code which requires use to pass instances of classes using void* */

        void *vp_base = new Base(123);
        void *vp_derived = new Derived(456,123);

/* handle_void_ptr needs to be used with caution. The programmer must only ever call it passing it a pointer nown to be an instance of a class derived from the polymorphic Base class */

        std::cout << "Handling vp_base...\n";
        handle_void_ptr(vp_base);

        std::cout << "Handling vp_derived...\n";
        handle_void_ptr(vp_derived);
}

// Handle a void pointer
void handle_void_ptr(void *vp)
{

/* We've agreed that this function is only to be used for classes derived from Base, for some system reason we had to pass the pointer as a void* and here we reinterpret the pointer as a pointer to an instance of the polymorphic Base class. This is evil, but necessary. */

        Base *base = reinterpret_cast<Base*>(vp);

/* Use a dynamic cast to attempt to downcast it to a Derived class */

        Derived *derived = dynamic_cast<Derived*>(base);
        if (derived != 0) {
                std::cout << "Successfully downcast the Base pointer to a Derived pointer using dynamic_cast\n";
                derived->print();
                derived->printv();
        }
        else
                std::cout << "Unable to downcast the Base pointer to a Derived pointer using dynamic_cast\n";

        base->print();
        base->printv();

        std::cout << '\n';
}
--------8<--------

I hope this helps.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question