あなたは質問をして、別の理由で失敗するコード例を提供しています。あなたの質問の文言から:
ポリモーフィズムに参照/ポインタが必要なのはなぜですか?
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 の一時オブジェクトで動作し、呼び出されます。derivedbasecall1dbasebase::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*コンテナーに挿入することができ、それは多くの問題を意味します...
しかし、問題は値型のコンテナに関するものでした...
値型のコンテナーがある場合、要素はコンテナーにコピーされます。derivedtypeのコンテナにtype の要素を挿入すると、オブジェクト内baseに type のサブオブジェクトのコピーが作成されます。それは上記と同じスライスです。それは言語の制限であることに加えて、正当な理由があります。オブジェクトのコンテナーがある場合、要素だけを保持するスペースがあります。より大きなオブジェクトを同じコンテナーに格納することはできません。そうしないと、コンパイラは各要素にどれだけのスペースを確保するかさえ知りません (後でさらに大きな型で拡張するとどうなるでしょうか?)。basederivedbasebase
他の言語では、これが実際に許可されているように見えるかもしれませんが (Java)、そうではありません。唯一の変更点は構文にあります。Java を使用しているときは、実際には C++String array[]と同等のものを書いています。string *array[]すべての非プリミティブ型は言語の参照であり*、構文に を追加しないという事実は、コンテナーが String のインスタンスを保持することを意味しません。コンテナーは String への参照を保持します。これは、c++ 参照よりも c++ ポインターに関連しています。 .