C++ Downcasting to Derived Class based off Variable

If they've virtual functions, then use dynamic_cast:

t = dynamic_cast<Triangle*>(shape);
if ( t )
{
     //use t
}

But take a note: you should try defining the classes and virtual functions in such a way that you would hardly need to use dynamic_cast. Prefer well-defined interface, and polymorphism, in general.

Here is one example,

class Shape
{
   public:
     virtual ~Shape() {} //destructor must be virtual - important!
     virtual double Area() const = 0;
};

class Triangle : public Shape
{
   public:
     Triangle(double a, double b, double c);
     virtual double Area() const 
     {
         //calculate area and return it!
     }
};

Shape *s = new Triangle(10, 20, 30);
double aread = s->Area(); //calls Triangle::Area()

No need to use shapeType variable.


The dynamic_cast is the answer to your problem.

Description

It is used to downcast from a base class into a derived class, all the while making it sure the cast fails should the derived class not be what you think. For example :

void foo(Shape * p_shape)
{
   Triangle * t = dynamic_cast<Triangle *>(p_shape) ;

   // if p_shape is a triangle, or derives from triangle,
   // then t is non-NULL, and you can use it
}

The point is that t will be non-NULL even if p_shape is not exactly a Triangle, but still inherits for triangle. For example, in the case :

Shape
 |
 +-- Square
 |
 +-- Triangle
      |
      +-- EquilateralTriangle
      |
      +-- RectangleTriangle

if shape is a Triangle, or an EquilateralTriangle, or a RectangleTriangle, then t will not be NULL, which is a lot more powerful than your initial solution of marking the exact type using a constant number.

Please note that for the dynamic_cast to work on a class, this class should have at least a virtual method (which is usually the case in the tree-inheritance hierarchy the dynamic_cast is used on)

Throwing dynamic_cast

Instead of using pointers, you could use references, but with references, as the dynamic_cast has no way to return a "failed reference", it will throw a std::bad_cast, which you can catch if necessary:

void foo(Shape & p_shape)
{
   Triangle & t = dynamic_cast<Triangle &>(p_shape) ;

   // if p_shape is a triangle, or derives from triangle,
   // then the dynamic_cast succeeds.
   // If not, a std::bad_cast is thrown
}

dynamic_cast abuse?

To be noted, the pointer-based non-throwing dynamic cast can lead to switch-like code (but if you can't rely on virtual methods, then you'll have to "switch on types"...):

void foo(Shape * p_shape)
{
   if(Triangle * t = dynamic_cast<Triangle *>(p_shape))
   {
      // if p_shape is a triangle, then t is non-NULL,
      // and you can use it
   }
   else if(Square * s = dynamic_cast<Square *>(p_shape))
   {
      // if p_shape is a square, then t is non-NULL
      // and you can use it
   }
   // etc...

Like all "switch on types" code, this is error prone (what if you forget to handle a type ?), but sometimes can't avoided, so it was worth mentioning.

(As a curiosity bonus, IIRC, the if(type * p = ...) notation was at first added to C++ to handle this case and make the code less verbose... Unless I missed something, this notation is not authorized in C#)

RTTI

All in all, the dynamic_cast relies on RTTI (RunTime Type Information), which can sometimes be disabled (at work, until a few years ago, it was decided by "technical experts" that it was unnecessary and thus mandatory to be disabled in our builds... Aaah, the "C-with classes experts"...)

Don't let yourself get caught in a C vs. C++ war: Unless you are working in very constrained environment (i.e. embedded development), RTTI (as all other C++ features like exception handling) should be activated.

More info on RTTI : http://www.cplusplus.com/reference/std/typeinfo/

And perhaps my Stack Overflow question on RTTI will interest you : C++ RTTI Viable Examples


You are doing it wrong. If you have to downcast like that you most likely have a very serious design flaw. Virtual member functions should be the solution.

If you really must downcast like this use dynamic_cast.