9

s->duplicate()タイプ のオブジェクトを返しますが、 でBox*初期化するとエラーが発生しますBox*。に変換されているようShape*です。基本クラスのポインターに変換された場合、共変の戻り値の型を持つことのポイントは何ですか?:

struct Shape
{
    virtual Shape* duplicate()
    {
        return new Shape;
    }
};

struct Box : Shape
{
    virtual Box* duplicate()
    {
        return new Box;
    }
};

int main()
{
    Shape* s = new Box;
    Box*   b = s->duplicate();
}

エラー:

main.cpp:22:12: error: cannot initialize a variable of type 'Box *' with an rvalue of type 'Shape *'
    Box*   b = s->duplicate();
           ^   ~~~~~~~~~~~~~~
1 error generated.
4

2 に答える 2

11

は実行時に (仮想ディスパッチを介して) 呼び出され、Box::duplicate (共変に)オーバーライドBox::duplicate 、 を返します、ポインターを介して呼び出しているため、引き続きポインターを取得し、は の戻り値の型であり、コンパイラは、あなたが呼び出しているのを見るだけで、 ではありません。Shape::duplicateBox::duplicate Box*Shape*duplicate()Shape*Shape*Shape::duplicate()Shape::duplicateBox::duplicate

C++ は型を動的に選択できないため、これが最善の方法です。あなたのはの途中でBox*に自動的に変換されています。Barry が言ったように、「コンパイル時にまだコンパイルする必要があり、コンパイル時にわかっているのは、それが".Shape*Box::duplicateShape*

次に、それを再び にするには、暗黙的なダウンコンバージョンが存在しないため、Box*明示的にキャストする必要があります ( static_castorを使用)。dynamic_cast

[C++11: 10.3/7]: オーバーライド関数の戻り値の型は、オーバーライドされた関数の戻り値の型と同じか、関数のクラスと共変でなければなりません[..]

[C++11: 10.3/8]:の戻り値の型が の戻り値の型とD::f異なる場合、 の戻り値の型B::fのクラス型は、D::fの宣言の時点で完全であるD::fか、クラス型である必要がありDます。オーバーライド関数がオーバーライドされた関数の最終オーバーライドとして呼び出されると、その結果は (静的に選択された) オーバーライドされた関数(5.2.2) によって返される型に変換されます。[..]

標準テキストでは、適切な例を次に示します。

于 2015-05-09T20:44:31.843 に答える