ただ興味がない...
size()
コンテナのライブラリを設計する場合、とのようなメソッドの(おそらく抽象的な)宣言を持つ共通の基本クラスから確実に派生しますinsert()
。
標準ライブラリコンテナがそのように実装されない強い理由はありますか?
ただ興味がない...
size()
コンテナのライブラリを設計する場合、とのようなメソッドの(おそらく抽象的な)宣言を持つ共通の基本クラスから確実に派生しますinsert()
。
標準ライブラリコンテナがそのように実装されない強い理由はありますか?
C++ では、継承はランタイム ポリモーフィ (ランタイム インターフェイスの再利用) に使用されます。実行時に vtable を介したリダイレクトのオーバーヘッドが発生します。
複数のコンテナー クラスに対して同じインターフェイスを使用する (API が予測可能であり、アルゴリズムが想定できるようにする) ために、継承は必要ありません。それらに同じメソッドを与えるだけで完了です。C++ のコンテナー (およびアルゴリズム) はテンプレートとして実装されます。つまり、コンパイル時のポリモーフィが得られます。
これにより、実行時のオーバーヘッドが回避され、「必要な分だけ支払う」という C++ のマントラに沿ったものになります。
Javaコレクション(おそらくあなたが念頭に置いている)には、で実装された一連の一般的なメソッドがあり、具象クラスで実装されたメソッドとメソッドAbstractCollection
の上にあります。それからIIRCにはそのような方法がもっとあります。一部のサブクラスはこれらのメソッドのほとんどをオーバーライドしますが、必要な抽象メソッドよりも少しだけ実装することで回避できるサブクラスもあります。一部のメソッドは、インターフェイスを共有するほとんどまたはすべてのコレクションに共通して実装されています。たとえば、変更不可能なビューを提供するのは、私の苦い経験では、書くべき完全なPITAです。size()
iterator()
AbstractList
C ++コンテナーには、すべてのコンテナーに共通するいくつかのメンバー関数がありますが、すべてのコンテナーに同じ方法で実装できるものはほとんどありません[*]。イテレータ(のような)を使用して実行できる一般的なアルゴリズムがある場合、それらは、継承が調べられる場所から遠く離れた、のfind
無料の関数です。<algorithm>
すべてのシーケンス、すべての連想配列などに共通するメンバー関数もあります。しかし、これらの概念のそれぞれについて、異なる具体的なデータ構造の実装間で共通することはあまりありません。
したがって、最終的には設計哲学の問題になります。JavaとC++はどちらも、コンテナに関してコードを再利用しています。C ++では、このコードの再利用は、の関数テンプレートを介して行われ<algorithm>
ます。Javaでは、その一部は継承によってもたらされます。
主な実際的な違いは、おそらくJavaでは、関数がjava.util.Collection
コレクションの種類を知らなくても受け入れることができるということです。C ++では、関数テンプレートは任意のコンテナーを受け入れることができますが、非テンプレート関数は受け入れることができません。これはユーザーのコーディングスタイルに影響を与え、それによっても通知されます。Javaプログラマーは、C++プログラマーよりもランタイムポリモーフィズムに到達する可能性が高くなります。
実装者の観点からすると、C ++コンテナーのライブラリーを作成している場合、std
コードの再利用に役立つと思われる場合は、の異なるコンテナー間でプライベート基本クラスを共有することを妨げるものは何もありません。
[*]これはC++11でsize()
保証されているので、おそらく共通して実装できます。C ++ 03では、単に「すべき」であり、サイズを更新するのではなく、これを利用してinのバージョンの1つを実装する実装がありました。O(1)
empty()
size()
O(1)
std::list
splice
O(1)
O(n)
別の観点から言えば、現在、それらを一般的な方法で使用すると、コンパイラーは持つことができるほぼすべての情報を持っているため、徹底的な最適化が可能になります。テンプレートの実装に感謝します。
たとえば、リストとベクトルの両方が push_backable のような抽象 OO インターフェイスを実装し、コードで抽象ポインタ (push_backable*)->push_back(...) を使用すると、コンパイラは多くの情報を失い、したがって、最適化の機会。
これらは、内側のループに現れる典型的な操作であり、可能な限り最大限に最適化する必要があります。Frerich Raabeの回答も参照してください。
このような基本クラスを導入する正当な理由はありません。誰がそれから利益を得ますか?どこで役に立ちますか?
「ジェネリック」インターフェースを必要とするアルゴリズムは、反復子を使用します。異なるコンテナーに要素を挿入する一般的な方法はありません。実際、一部のコンテナには要素を挿入することさえできません。
使用しているコンテナーに依存しないコードを記述できれば、それは理にかなっています。しかし、そうではありません。『 Effective STL 』の「項目 2: コンテナに依存しないコードの錯覚に注意する」という章を読むことをお勧めします。