Solved

dynamic_cast code crashes on vc++

Posted on 2003-11-11
3
501 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
  • 2
3 Comments
 
LVL 17

Accepted Solution

by:
rstaveley earned 50 total points
Comment Utility
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
Comment Utility
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
Comment Utility
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Unlike C#, C++ doesn't have native support for sealing classes (so they cannot be sub-classed). At the cost of a virtual base class pointer it is possible to implement a pseudo sealing mechanism The trick is to virtually inherit from a base class…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
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 learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

762 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now