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

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

本文关键字:C++ 派生 类似于 基类 指针      更新时间:2023-10-16

如果我从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()"

编辑根据下面的响应,我尝试将basePtr对象动态转换为CCircle,如下所示:

CCircle *circle = new CCircle(1, 2, 3.3);
basePtr = dynamic_cast<CCircle *>(circle);

然而,这也失败了。我从未做过dynamic_cast,也不熟悉C++中的大多数语法,因此非常感谢您的帮助。

您可能会小心使用强制转换。首先,dynamic_cast添加了用于检查指针类型的运行时开销(请参见rtti)。static_cast要便宜得多,但不检查对象的动态类型。

向下广播表示可能(!)在您的设计中出现错误。决不是总是这样,但尤其是当你正在学习C++OOP时,尽量避免它们。

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

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


编辑:了解的原因

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

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

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

要获得getRadius函数,必须声明其类型为CCircle:

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

否则,如果您想将basePtr声明为CShape,请使用与dynamic_cast的动态绑定,或者直接使用c样式转换,正如@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();

您可以执行静态强制转换(http://www.cplusplus.com/doc/tutorial/typecasting/)从CShape到Circle

或者,您可以在CShape中将getRadius()声明为一个虚拟函数,考虑到类的名称,您可能不想这样做。