4

如果我从我的 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++ 中的大部分语法,因此非常感谢任何帮助。

4

3 回答 3

4

你可能会小心演员表。首先dynamic_casts 增加了检查指针类型的运行时开销(参见rtti)。static_casts 便宜很多但不检查对象的动态类型。

向下转型是您的设计可能(!)有问题的指标。情况并非总是如此,但尤其是如果您正在学习 C++ OOP,请尽量避免使用它们。

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

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


编辑:了解原因

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

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

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

于 2012-08-04T23:25:55.543 回答
2

getRadius发挥作用,您必须声明它的类型CCircle

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

否则,如果您想声明basePtrCShape,请使用动态绑定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();
于 2012-08-04T22:01:32.057 回答
0

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

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

于 2012-08-04T22:09:24.190 回答