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にdynamic_castしようとしました。

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

しかし、これも失敗しました。私はdynamic_castを行ったことがなく、C ++の構文のほとんどに慣れていないため、助けていただければ幸いです。

4

3 に答える 3

4

キャストには注意が必要かもしれません。まず最初にdynamic_cast、ポインタのタイプをチェックするための実行時オーバーヘッドを追加します(rttiを参照)。static_castsははるかに安価ですが、オブジェクトの動的タイプをチェックしないでください。

ダウンキャストは、設計に何か問題がある可能性がある(!)ことを示す指標です。これが常に当てはまるわけではありませんが、特にC ++ OOPを学習している場合は、それらを回避するようにしてください。

にを追加することは意味がないgetRadiusためCShape(すべての形状に半径があるわけではないため)、を処理する関数はCShape*、オブジェクトがであることに依存するべきではありませんCCircle

たとえば、形状の面積を決定しようとしている可能性があります。これはおそらくすべての形状にとって意味のあることなのでvirtual、形状の面積を計算する抽象関数を追加します。次に、円は半径を使用してこれを実装し、長方形は辺の長さの積を使用して実装します。


編集:理由を理解するため

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

動作しません。C++は強く型付けされていることを理解する必要があります。getRadius2行目では、から呼び出されたメンバーにアクセスしようとしています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();

それ以外の場合、basePtrとして宣言する場合は、@ Janiszが指摘したように、CShape動的バインディングを使用するか、cスタイルのキャストを直接使用します。dynamic_cast

       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/ )を実行できます。

または、getRadius()をCShapeの仮想関数として宣言することもできます。これは、クラスの名前を指定して実行したくない場合があります。

于 2012-08-04T22:09:24.190 に答える