使基类指针在C ++中的行为类似于派生类

时间:2012-08-04 21:58:51

标签: c++ inheritance pointers

如果我从Shape基类中创建一个指针,我怎么能让它像圆(派生)类一样?以下是我的班级定义:

    //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;
        }
    };

在我调用这些对象的项目文件中,我有以下代码:

            CShape *basePtr = new CCircle(1, 2, 3.3);
            basePtr->getRadius();

在我看来,这应该可行,但我告诉CShape没有成员“getRadius()。”

EDIT 根据下面的响应,我尝试将basePtr对象dynamic_cast成CCircle,如下所示:

CCircle *circle = new CCircle(1, 2, 3.3);
basePtr = dynamic_cast<CCircle *>(circle);
然而,这也失败了。我从来没有做过dynamic_cast,也不熟悉C ++中的大部分语法,所以非常感谢任何帮助。

3 个答案:

答案 0 :(得分:4)

你可能会对演员阵容小心。首先,dynamic_cast添加运行时开销以检查指针的类型(请参阅 rtti )。 static_cast更便宜但不检查对象的动态类型。

向下倾斜是可能(!)在您的设计中出现问题的指标。绝不是这种情况,尤其是如果你正在学习C ++ OOP试着避免它们。

由于向getRadius添加CShape没有意义(因为并非所有形状都有半径),处理CShape*的函数不应依赖于对象是CCircle

例如,您可能正在尝试确定形状的区域。对于所有形状而言,这可能是一件有意义的事情,因此您需要添加一个virtual抽象函数来计算形状的面积。然后你的圆圈将通过使用它的半径来实现它,使用它的边长的乘积来实现矩形等等。


编辑:了解原因

CShape *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();

无法工作,你必须明白C ++是强类型的。在第二行中,您尝试从getRadius访问名为CShape的成员。该类(或其任何父类)没有这样的成员。确实(在程序运行时)变量basePtr指向类型为CCircle的对象,但在编译时无法知道(在一般情况下,即)。因此,C ++甚至懒得检查派生类型,因为(再次,一般而言)它根本不能。在编译这一行时,它甚至可能知道所有派生类型,因此它没有机会理解你的意图。

就编译器而言,basePtr可能指向一个具有getRadius成员的类型的对象。

答案 1 :(得分:2)

要获得getRadius功能,您必须声明类型CCircle

        CCircle *basePtr = new CCircle(1, 2, 3.3);
        basePtr->getRadius();

否则,如果您要将basePtr声明为CShape,请使用动态绑定dynamic_cast或直接使用c-style强制转换,如@Janisz所指出的那样。

       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();

答案 2 :(得分:0)

你可以从CShape到Circle

进行静态演员(http://www.cplusplus.com/doc/tutorial/typecasting/

或者,您可以将getRadius()声明为CShape中的虚函数,在给定类的名称时您可能不想这样做。