あなたは質問をして、別の理由で失敗するコード例を提供しています。あなたの質問の文言から:
ポリモーフィズムに参照/ポインタが必要なのはなぜですか?
struct base {
virtual void f();
};
struct derived : public base {
virtual void f();
};
void call1( base b ) {
b.f(); // base::f
}
void call2( base &b ) {
b.f(); // derived::f
}
int main() {
derived d;
call1(d);
call2(d);
}
値渡しセマンティクスを使用する (またはベース コンテナーに派生要素を格納する) 場合、 typebase
の要素のtype のコピーを作成していますderived
。これは、オブジェクトがあり、そのサブオブジェクトのみをスライス/カットするという事実に似ているため、スライスと呼ばれます。この例では、 は mainのオブジェクトからではなく、 type の一時オブジェクトで動作し、呼び出されます。derived
base
call1
d
base
base::f
メソッドではcall2
、オブジェクトへの参照を渡していbase
ます。コンパイラがcall2(d)
in main を確認すると、base
サブオブジェクト inへの参照が作成d
され、関数に渡されます。この関数は、 型base
のオブジェクトを指す型 の参照に対して操作を実行しderived
、 を呼び出しますderived::f
。ポインターでも同じことが起こります。オブジェクトに を取得するbase *
とderived
、オブジェクトはまだderived
です。
derived
ポインターのコンテナーを受け取る関数にポインターのコンテナーを渡すことができないのはなぜbase
ですか?
_明らかderived
にbase
、 のコンテナderived
はのコンテナですbase
。
いいえ。 のコンテナは のコンテナでderived
はありませんbase
。それは型システムを壊します。型システムを破るオブジェクトのderived
コンテナーとしてのコンテナーを使用する最も単純な例を以下に示します。base
void f( std::vector<base*> & v )
{
v.push_back( new base );
v.push_back( new another_derived );
}
int main() {
std::vector<derived*> v;
f( v ); // error!!!
}
エラーでマークされた行が言語で許可されている場合、アプリケーションは型ではない要素をderived*
コンテナーに挿入することができ、それは多くの問題を意味します...
しかし、問題は値型のコンテナに関するものでした...
値型のコンテナーがある場合、要素はコンテナーにコピーされます。derived
typeのコンテナにtype の要素を挿入すると、オブジェクト内base
に type のサブオブジェクトのコピーが作成されます。それは上記と同じスライスです。それは言語の制限であることに加えて、正当な理由があります。オブジェクトのコンテナーがある場合、要素だけを保持するスペースがあります。より大きなオブジェクトを同じコンテナーに格納することはできません。そうしないと、コンパイラは各要素にどれだけのスペースを確保するかさえ知りません (後でさらに大きな型で拡張するとどうなるでしょうか?)。base
derived
base
base
他の言語では、これが実際に許可されているように見えるかもしれませんが (Java)、そうではありません。唯一の変更点は構文にあります。Java を使用しているときは、実際には C++String array[]
と同等のものを書いています。string *array[]
すべての非プリミティブ型は言語の参照であり*
、構文に を追加しないという事実は、コンテナーが String のインスタンスを保持することを意味しません。コンテナーは String への参照を保持します。これは、c++ 参照よりも c++ ポインターに関連しています。 .