4

このプログラムは例外なく実行されます。動的キャストと静的キャストが成功する理由を説明してください。そして、C ++はどのようにして必要な仮想関数を解決するのでしょうか?

class Shape 
    {
    private :
        string helperFunction();

    public : 
        virtual void draw() = 0;
        virtual void type();
    };

void Shape::type()
    {
    cout << "Shape Type";
    }

// ----------------------------------------------------------------------------

class Circle : public Shape
    {
    private: 
    string circlething;

    public :
        virtual void draw();
        virtual void type();
        void CircleFunction();
    };

void Circle::draw()
    {
    cout <<"Circle Draw" << endl;
    }

void Circle::type()
    {
    cout <<"Circle Type" << endl;
    }

void Circle::CircleFunction()
    {
    circlething = "Circle Thing";
    cout << circlething;
    cout << "Circle Function" << endl;
    }


class Square : public Shape
    {
    private :
        string  squarething;
    public :
        virtual void draw();
        virtual void type();
        void SquareFunction();
    };

void Square::draw()
    {
    cout <<"Square Draw" << endl;
    }

void Square::type()
    {
    cout <<"Square Type" << endl;
    }

void Square::SquareFunction()
    {
    squarething = "Square Thing";
    cout << squarething;
    cout << "Square Function" << endl;
    }
// ----------------------------------------------------------------------------


int _tmain(int argc, _TCHAR* argv[])
    {
    vector<Shape *> shapes;
    Circle circle;
    Square square;
    shapes.push_back(&circle);
    shapes.push_back(&square);

    vector<Shape *>::const_iterator i;

    for (i = shapes.begin(); i < shapes.end(); ++i)
        {

        cout << "\n*** Simple Type ***\n" << endl;
        (*i)->type();
        (*i)->draw();

        cout << "---Static Cast Circle--" << endl;
        Circle* circle = static_cast<Circle*>(*i);
        circle->type();
        circle->draw();
        circle->CircleFunction();

        cout << "---Static Cast Square--" << endl;
        Square* square = static_cast<Square*>(*i);
        square->type();
        square->draw();
        square->SquareFunction();

        cout << "---Static Cast Circle to Shape --" << endl;
        Shape* shape1 = static_cast<Shape*> (circle);
        shape1->type();
        shape1->draw();

        cout << "--- Dynamic Cast Circle to Shape --" << endl;
        Shape* shape2 = dynamic_cast<Shape*> (circle);
        shape2->type();
        shape2->draw();

        cout << "--- Static Cast Square to Shape --" << endl;
        Shape* shape3 = static_cast<Shape*> (square);
        shape3->type();
        shape3->draw();

        cout << "--- Dynamic Cast Square to Shape --" << endl;
        Shape* shape4 = dynamic_cast<Shape*> (square);
        shape4->type();
        shape4->draw();

        }
    int x;
    cin >> x;
    return 0;
    }
4

4 に答える 4

4

例外をスローしない理由から始めましょう。非常に単純なので、参照dynamic_castをキャストしようとすると例外がスローされ、失敗します。ポインターで使用すると、成功した場合はポインターが返され、失敗した場合は null ポインターが返されます。dynamic_cast

キャストが失敗したことがない理由については、すべて階層dynamic_cast上っShape *て. 問題のすべてのオブジェクトはから派生してShapeいるため、これは常に成功します。実際、その変換は暗黙的に行うことができます。

実際に何をしようとしているのかを示すためdynamic_castに、少し異なるコードを書いてみましょう:

#include <iostream>
#include <vector>

using namespace std;

class Shape {
public : 
    virtual void draw() = 0;
};

class Circle : public Shape
{
public :
    virtual void draw() { cout << "Circle Draw\n"; }
    void circlefunc() { cout << "circle func\n"; }
};

class Square : public Shape
{
public :
    virtual void draw() { cout << "Square Draw\n"; }
    void squarefunc() { cout << "Square Func\n"; }
};

int main() {
    vector<Shape *> shapes;
    Circle circle;
    Square square;
    shapes.push_back(&circle); // implicit conversion from Circle * to Shape *
    shapes.push_back(&square); // implicit conversion from Square * to Shape *

    Circle *c;
    Square *s;
    for (int i=0; i<shapes.size(); i++) {
        shapes[i]->draw(); // draw polymorphically
        if (c = dynamic_cast<Circle *>(shapes[i])) // try to cast to Circle *
            c->circlefunc();               // if it worked, invoke circlefunc
        else if (s = dynamic_cast<Square *>(shapes[i])) // likewise for square
            s->squarefunc();
    }
    return 0;
}

今回は、dynamic_cast を使用してShape *toSquare *またはから取得しCircle *ます。これは、指示先オブジェクトの動的タイプがそのタイプである場合にのみ成功します。それ以外の場合は、null ポインターが生成されます。null 以外のポインターを取得した場合にのみ、その特定の型のメンバー関数を呼び出します。

要約すると、派生オブジェクトへのポインター/参照がある場合、基本クラスへのポインター/参照に暗黙的に変換できます。これは常に安全であるため、必要ありませんdynamic_cast(または明示的なキャストはまったく必要ありません)。

ポインター/参照からベースへの変換を行って派生へのポインター/参照を取得する場合、通常はdynamic_cast. これは、指示先オブジェクトの実際のタイプ (つまり、動的タイプ) が目的のターゲット (またはそのベース) であるかどうかに基づいて成功/失敗します。この場合、ポインターまたは参照のどちらを操作しているかに応じて、失敗のシグナルが異なります。参考までに、失敗すると例外がスローされます。ポインターの場合、失敗すると null ポインターが生成されます。

于 2012-05-04T14:57:30.353 に答える
3

なぜそれが必要なのですか?dynamic_castキャストが失敗した場合に返さNULLれ、ポインターの例外はスローされません。

また、それはさておき、なぜ失敗するのでしょうか。もSquareもs ですCircleShapeだからキャストはいい。

基本的なポリモーフィズムのため、出力はご覧のとおりです。オブジェクトまたはオブジェクトShape*を指す があります。関数呼び出しは、最も派生したクラスからオーバーライドされたメソッドを呼び出します。これはOOPの中心的な側面です。SquareCirclevirutal

ほとんどの実装では、これは を通じて達成されvirtual function tablesます。がありますがShape*、オブジェクトは仮想関数テーブルへのポインターを内部に保持します。Squareそのメンバーはキャスト中に変更されないため、 aまたは aの仮想関数テーブルを指しCircle、呼び出しは正しく解決されます。

ここに画像の説明を入力

于 2012-05-04T14:56:15.487 に答える
1

dynamic_cast派生型から基本型への変換を使用しており、あいまいさはありません。なぜそれが失敗すると思ったのですか?また、dynamic_castonポインターを使用しても、例外はスローされません(代わりに)が返されNULLます。タイプ参照間でキャストするときに例外をスローする可能性があります。

static_cast単純なクラスの構築方法により、成功します。CircleFunction()およびSquareFunction()は実際には無効なクラスメンバー変数にアクセスしようとしないため、プログラムは正常に(幸運にも)実行できます。を使用して型間で誤って変換することはstatic_cast、実行すべきことではありません。

于 2012-05-04T14:59:15.827 に答える
0

簡単な答え: static_cast<Square>Circle ポインターとstatic_cast<Circle>Square ポインターで を実行しているときは、未定義の動作に陥っています。その時点でほとんど何でも起こり得ます。

また、 を呼び出すとdynamic_cast、ポインターにキャストしている場合、失敗して NULL を返す可能性があります。参照に変換している場合にのみ、例外がスローされます。また、コンパイル時にあいまいさがないことがわかっている場合、コンパイラは dynamic_cast をコンパイル時のキャストに置き換えることを選択できます (ここでは、子から親へキャストしているため)。

あなたが得ている出力は、クラスが互いに十分に似ているため、キャストは合法ではありませんが、とにかくうまくいきました. 未定義の動作を考えると、変更を続ければそれに頼ることは不可能です。

于 2012-05-04T15:02:13.923 に答える