2017-12-28 23 views
2

継承によって2つの単純なクラスを作成し、子クラスに仮想関数とオーバーライドを追加します。C++:ポインタのない共変な戻り値型

この場合
class Parent 
{ 
public: 
    virtual Parent foo(); 
}; 

class Child : public Parent 
{ 
public: 
    Child foo() override; 
}; 

は、私のオーバーライドされた関数がエラーを取得する:error C2555: 'Child::foo': overriding virtual function return type differs and is not covariant from 'Parent::foo'

私はポインタと戻り値の型を変更する場合:

class Parent 
{ 
public: 
    virtual Parent* foo(); 
}; 

class Child : public Parent 
{ 
public: 
    Child* foo() override; 
}; 

エラーがなくなって! 戻り値の型の共分散をポインタで行う必要があり、値型または参照を使用できない理由を理解できません。 一部のWebサイトまたはフォーラムでは、戻り値が関数で使用される値のコピーであるため、コンパイラはポインタの定数サイズを認識しますが、オーバーライドされた関数と親関数のサイズが異なる必要があります。

この場合、ポインタ以外のものを使用できないのはなぜですか? ポインタを使用せずにオーバーライドされた関数で子タイプを使用する場合は、各関数の基本クラスを返し、返されたタイプを子タイプにキャストする必要がありますか?

+1

マイナーサイド以外:ポインタを使用する必要はありません。参照も使用できます。 –

+1

"関数を使用しないで関数ごとに基本クラスを返し、返された型を子型にキャストする必要があります。"いいえ、親オブジェクトを子にキャストできません。返されるオブジェクトは完全なオブジェクトです。子はありません。 'return child;と言うと、返す子オブジェクトはスライスされ、' Parent'部分だけのコピーが返されます。 –

答えて

5

共変戻り値の型のアイデアはpolymorpihcの戻り値の型です。そしてC++では、ポインタや参照なしで実行時の多態性を持つことはできません。苦難の第二の大部分を無視し、それが可能であるとふりましょう。ここにあなたのParentインタフェースで物事を処理する私のコードは次のとおりです。

void bar(Parent * p) { 
    auto o = p->foo(); 
} 

oは何?もちろん、Parentです。 Parent::fooの戻り値の型にそう言います。しかし、pChildを指している場合はどうなりますか?推測タイプoはまだParentなので、せいぜいスライスされたオブジェクトが得られます。多形的な振る舞いはないので、全体の運動は無意味です。

最悪の場合、おそらく未定義の動作が発生します。

だからこそ、共変種の戻り値の型はポインタまたは参照でなければなりません。

0

これは、派生型が派生インスタンスを返すが、呼び出し側が親を予期しているためです。これはポインタを使用するときとは異なります。派生ポインタが親ポインタ用に確保された領域実際のインスタンスについて話すときは同じではありません。また、派生したメソッドが派生したインスタンスを返すが、親ポインタを使用している呼び出し元はそれについては考えていないので、おそらく親パーツだけを破壊するという問題があります。

あなたは見つけることができますthis役立つ

関連する問題