1. ホーム
  2. c++

なぜポインタ/参照がないとポリモーフィズムは機能しないのか?

2023-11-17 08:26:41

疑問点

SOで似たようなタイトルの質問をいくつか見つけましたが、回答を読むと、質問の異なる部分に焦点を合わせていて、本当に具体的でした (例: STL/コンテナ)。

なぜポリモーフィズムを実装するためにポインタや参照を使用しなければならないのか、どなたか教えていただけませんか?私はポインタが役立つかもしれないことを理解できますが、確かに参照は値渡しと参照渡しを区別するだけでしょうか?

確かに、ヒープ上にメモリを確保し、動的バインディングができるようにすれば、それで十分だったのでしょうが、明らかにそうではありません。

どのように解決するのですか?

C++では、オブジェクトは常にコンパイル時に既知の固定型とサイズを持ち、(アドレスを取得することが可能である場合) その寿命の間、常に固定アドレスに存在します。これらはC言語から受け継いだ機能であり、両言語を低レベルのシステムプログラミングに適したものにするのに役立っている。(これらはすべて as-if のルールに従いますが、規格に準拠したコンパイラーは、規格によって保証された準拠プログラムの動作に検出可能な影響を与えないことが証明できる限り、コードに対して自由に好きなことを行うことができます)。

A virtual 関数は、オブジェクトの実行時型に基づいて実行されると定義されています(多かれ少なかれ、極端な言語処理は必要ありません)。 virtual 関数がこの方法で呼び出された場合、ポリモーフィズムはありません。

これは必ずしもそうである必要はなかったことに注意してください:オブジェクト型に virtual 関数を持つオブジェクト型は、通常 C++ で実装され、オブジェクトごとのポインタが virtual 関数のテーブルへのオブジェクトごとのポインタを使用して実装されます。もしその気になれば、C++ のある仮想的な変種のコンパイラは、オブジェクトへの代入(たとえば Base b; b = Derived() のような) オブジェクトへの代入を、オブジェクトのコンテンツと virtual テーブルポインタの両方をコピーするものとして扱われます。 BaseDerived が同じサイズであった場合。2 つが同じサイズでない場合、コンパイラーは、プログラム内のメモリを再配置し、プログラムのセマンティクスに検出可能な影響を与えないことが証明できる方法でそのメモリへのすべての可能な参照を更新するために、任意の時間、プログラムを一時停止するコードを挿入し、そのような再配置が見つからなかった場合にプログラムを終了することもできます。

そのため、上記の代わりに、C++ における多相性は、オブジェクトへの参照とポインタが、宣言されたコンパイル時の型とその任意のサブタイプのオブジェクトを参照およびポイントできるようにすることで実現されています。このとき virtual 関数が参照やポインタを通して呼び出され、参照または指されたオブジェクトがその virtual 関数が呼び出された場合、コンパイラは正しい virtual 関数を呼び出すコードを挿入します。参照やポインタをポリモーフィックでないと定義し(宣言された型のサブタイプを参照したり指し示したりすることを禁止し)、プログラマにポリモーフィズムを実装する別の方法を考えさせることも可能でした。後者は C 言語で常に行われているので明らかに可能ですが、その時点では新しい言語を持つ理由はあまりありません。

まとめると、C++のセマンティクスは、オブジェクト指向ポリモーフィズムの高レベルな抽象化とカプセル化を可能にする一方で、低レベルな開発に適した機能(低レベルなアクセスやメモリの明示的な管理など)を保持するように設計されているのです。他のセマンティクスを持つ言語を設計することは容易ですが、それはC++ではなく、異なる利点と欠点を持つことになるでしょう。