Reputation: 10689
If I create a pointer out of my Shape base class, how would I got about making it behave like the circle (derived) class? Here are my class definitions:
//CShape.h class definition
//Shape class definition
#ifndef CSHAPE_H
#define CSHAPE_H
class CShape
{
protected:
float area;
virtual void calcArea();
public:
float getArea()
{
return area;
}
};
class CCircle : public CShape
{
protected:
int centerX;
int centerY;
float radius;
void calcArea()
{
area = float(M_PI * (radius * radius));
}
public:
CCircle(int pCenterX, int pCenterY, float pRadius)
{
centerX = pCenterX;
centerY = pCenterY;
radius = pRadius;
}
float getRadius()
{
return radius;
}
};
In my project file where I'm calling these objects, I have the following code:
CShape *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
It seems to me like this should work, however I'm told CShape has no member "getRadius()."
EDIT Based on the response below I tried to dynamic_cast the basePtr object to CCircle like so:
CCircle *circle = new CCircle(1, 2, 3.3);
basePtr = dynamic_cast<CCircle *>(circle);
This failed too, however. I've never done a dynamic_cast and am unfamiliar with most of the syntax in C++, so any help is greatly appreciated.
Upvotes: 4
Views: 2341
Reputation: 34628
You might be careful with casts. First of all dynamic_cast
s add a runtime overhead for checking the type of your pointer (see rtti). static_cast
s are a lot cheaper but do not check the dynamic type of the object.
Downcasts are indicators that there might (!) be something wrong in your design. By no means is this always the case, but especially if you are learning C++ OOP try to avoid them.
Since it is not meaningful to add a getRadius
to CShape
(simply because not all shapes have a radius), a function that deals with a CShape*
shouldn't rely on the object being a CCircle
.
For example, you could be trying to determine the area of your shape. That's probably a meaningful thing for all shapes, so you would add a virtual
abstract function that computes the area for a shape. Your circle then would implement this by using it's radius, a rectangle by using the product of its side lengths and so forth.
Edit: To understand why
CShape *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
cannot work, you have to understand that C++ is strongly typed. In the second line, you are trying to access a member called getRadius
from CShape
. That class (nor any of its parent classes) has no such a member. It is true that (while your program runs) the variable basePtr
points to an object of type CCircle
, but that cannot be known at compile time (in the general case, that is). Thus, C++ doesn't even bother to check derived types, because (again, in general) it simply cannot. When compiling this line, it might not even know all derived types, so it has no chance to understand what you meant to do.
As far as the compiler is concerned, basePtr
could be pointing at an object that is of a type that does not have a getRadius
member.
Upvotes: 4
Reputation:
To get to getRadius
function you must declare it of type CCircle
:
CCircle *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
Otherwise, if you want to declare basePtr
as CShape
, use dynamic binding with dynamic_cast
or use c-style cast directly, as @Janisz pointed out.
CShape *basePtr = new CCircle(1, 2, 3.3);
CCircle *child
// choose one of the two ways, either this:
child = (CCircle*)basePtr; // C-style cast
// or this:
child = dynamic_cast<CCircle*>(basePtr); // C++ version
child->getRadius();
Upvotes: 2
Reputation: 1199
You can do a static cast ( http://www.cplusplus.com/doc/tutorial/typecasting/ ) from CShape to Circle
Alternatively, you could declare getRadius() as an virtual function in CShape, which you may not want to do given the name of the class.
Upvotes: 0