NealR
NealR

Reputation: 10689

Make base class pointer behave like derived class in C++

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

Answers (3)

bitmask
bitmask

Reputation: 34628

You might be careful with casts. First of all dynamic_casts add a runtime overhead for checking the type of your pointer (see rtti). static_casts 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

user586399
user586399

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

umps
umps

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

Related Questions