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
.