Regarding your example...
1) That's true if the classes are not polymorphic. If they are polymorphic, though, you can determine the type with typeinfo. A polymorphic class has at least 1 virtual member or virtual parent. (In Java everything is polymorphic so it's moot).
2) name() isn't the only means by which to identify the type. And in fact, it's unreliable as different compilers will yield different results.
Here's a example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
#include <iostream>
#include <typeinfo>
using namespace std;
class A
{
public:
virtual ~A() { } // virtual dtor to make it polymorphic
};
class B : public A {};
int main()
{
A* b1 = new A;
A* b2 = new B;
if(typeid(*b1) == typeid(B)) cout << "b1 is a B" << endl;
else cout << "b1 is not a B" << endl;
if(typeid(*b2) == typeid(B)) cout << "b2 is a B" << endl;
else cout << "b2 is not a B" << endl;
cin.get();
return 0;
}
|
But why shouldn't this be done? There is not much left of OOP if you shouldn't determine an object's type IMO. |
It's actually the opposite. OOP is destroyed if you need to know the exact type.
The whole point of abstracting with a parent class is so that you can write code to work with
any derived class. If you're determinig the type and/or downcasting, you're no longer writing code that is adaptable to different types.
Let's take the classic Area() example. Say you have a parent class "Shape" and derived classes "Rectangle" and "Circle". And say you have a function that takes a Shape* pointer and needs to calculate and print the area of that shape:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
// area of rectangle = width*height
// area of circle = pi*radius*radius
// now you might think that since the area for each shape is calculated a different way, that you need
// to determine what kind of shape it is and calculate the area based on that:
void printArea(Shape* shape)
{
int area;
if( typeid(*shape) == typeid(Circle) ) // is the shape a circle?
{
// if yes...
Circle* c = static_cast<Circle*>(shape); // downcast so we can access Circle members
area = c->radius * c->radius * pi; // calc the area
}
else if( typeid(*shape) == typeid(Rectangle) )
{
// otherwise, if the shape is a rectangle
Rectangle* r = static_cast<Rectangle*>(shape); // downcast
area = r->width * r->height;
}
cout << "The area is: " << area;
}
|
Of course, this is the
absolute wrong way to do this. Determining the type and downcasting has a big problem. It forces you to write code that will only work with specific classes.
What happens, for example, if a new shape 'Triangle' is created later. You would have to remember to update this function. But what if you're doing this in dozens of different areas in your program? Every time you add a new shape, you have to go back and modify each and every spot that checks the type. Hope you don't forget any!
The better way is to take advantage of polymorphism. Instead of determining the type, just deal with an abstract interface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
class Shape
{
public:
virtual int Area() = 0; // virtual function to calculate the area
};
class Circle
{
int radius;
public:
virtual int Area() { return radius * radius * pi; }
};
class Rectangle
{
int width, height;
public:
virtual int Area() { return width * height; }
};
//===================
void printArea(Shape* shape)
{
// now, it doesn't matter what kind of Shape we have... we can just do this:
cout << "The area is: " << shape->Area();
}
|
printArea doesn't need to know what kind of shape it has. All it needs to know is that it has some kind of Shape, and that Shapes have a way to calculate their area. The more the function assumes about the type, the less flexible it becomes.
This new printArea function not only works with Circles and Rectangles, but it will also work with
any and all shapes that may be created in the future. If you add a new shape, this function will work with it without any modifications.
Here's another post I made a little while ago that goes into more detail:
http://cplusplus.com/forum/beginner/28170/#msg152257