34

STL コンテナに仮想デストラクタがない理由を知っている人はいますか?

私が知る限り、唯一の利点は次のとおりです。

  • インスタンスのサイズを (仮想メソッド テーブルへの) 1 つのポインターだけ減らします。
  • 破壊と構築が少し速くなります。

欠点は、コンテナを通常の方法でサブクラス化するのは安全ではないことです。

編集: おそらく私の質問は、「継承を許可するように設計された STL コンテナーではなかったのはなぜですか?」と言い換えることができます。

それらは継承をサポートしていないため、STL 機能と少数の追加機能 (マップのデフォルト値を持つ特殊なコンストラクターまたは新しいアクセサーなど) を必要とする新しいコンテナーが必要な場合、次の選択肢に行き詰まります。または何でも):

  • コンポジションとインターフェイスのレプリケーション: STL コンテナーをプライベート メンバーとして所有し、STL メソッドごとに 1 つのパススルー インライン メソッドを持つ新しいテンプレートまたはクラスを作成します。これは継承と同じくらいパフォーマンスが高く、仮想メソッド テーブルのコストを回避できます (重要な場合)。残念ながら、STL コンテナーにはかなり幅広いインターフェイスがあるため、一見簡単に実行できるはずのコード行が多数必要になります。
  • Just make functions : メンバー関数を追加する代わりに、ファイル スコープの関数を使用します。いくつかの点でこれは良い方法かもしれませんが、カプセル化の利点は失われます。
  • パブリック STL アクセスによる構成: STL コンテナーの所有者に、ユーザーが STL コンテナー自体にアクセスできるようにします (おそらくアクセサーによって保護されます)。これにより、ライブラリ作成者のコーディングは最小限で済みますが、ユーザーにとってはあまり便利ではありません。コンポジションの大きなセールス ポイントの 1 つは、コード内の結合を減らすことですが、このソリューションでは、STL コンテナーと所有者コンテナーが完全に結合されます (所有者が真の STL コンテナーを返すため)。
  • コンパイル時のポリモーフィズム: 書くのがやや難しい場合があり、コードの体操が必要で、すべての状況に適しているわけではありません。

副次的な質問として、非仮想デストラクタを使用してサブクラス化する標準安全な方法はありますか (新しいメソッドを追加したいだけで、メソッドをオーバーライドしたくないと仮定しましょう)。私の印象では、非仮想クラスを定義するコードを変更する権限がない場合、これを行う一般的で安全な方法はありません。

編集2:

@docが指摘しているように、C++ 11 の洗練されusingた宣言により、構成のコストがいくらか削減されます。

4

9 に答える 9

29

仮想デストラクタは、継承のシナリオでのみ役立ちます。STL コンテナーは、継承されるように設計されていません (また、サポートされているシナリオでもありません)。したがって、仮想デストラクタはありません。

于 2009-10-30T00:15:34.490 に答える
18

Stroustrup は、彼の素晴らしい論文でこの質問に間接的に答えたと思います: Why C++ is not a ObjectOriented Programming Language :

7
おわりに 上記のさまざまな機能はオブジェクト指向ですか。どれ?オブジェクト指向のどの定義を使用していますか? ほとんどの場合、これらは間違った質問だと思います。重要なのは、どのアイデアを明確に表現できるか、さまざまなソースからのソフトウェアをどれだけ簡単に組み合わせることができるか、結果として得られるプログラムがいかに効率的で保守しやすいかです。つまり、優れたプログラミング手法と優れた設計手法をどのようにサポートするかは、ラベルやバズワードよりも重要です。基本的な考え方は、抽象化によって設計とプログラミングを改善することです。詳細を隠したい、システムの共通点を活用したい、そしてこれを手頃な価格にしたい. オブジェクト指向を無意味な用語にしないでください。「オブジェクト指向」の概念はあまりにも頻繁に貶められている

– それを善と同一視することによって、

– それを単一の言語と同一視することによって、または

– すべてをオブジェクト指向として受け入れることによって。

私は、オブジェクト指向のプログラミングや設計を超えた有用な手法が存在すること、そして存在するに違いないと主張してきました。ただし、完全な誤解を避けるために、少なくともオブジェクト指向プログラミングの古典的な概念をサポートしていないプログラミング言語を使用して本格的なプロジェクトを試みるつもりはないことを強調したいと思います。オブジェクト指向プログラミングをサポートする機能に加えて、概念と関係の直接的な表現をサポートする機能を超えた機能が必要であり、C++ が提供します。

STL は、主に 3 つの概念的なツールを念頭に置いて構築されました。汎用プログラミング + 関数型スタイル + データ抽象化 == STL スタイル. OOP がData Structure & Algorithms ライブラリを表現する最良の方法ではないことは不思議ではありません。OOP は標準ライブラリの他の部分で使用されていますが、STL の設計者は、上記の 3 つの手法を組み合わせた方が OOP単独よりも優れていることに気付きました。つまり、ライブラリは OOP を念頭に置いて設計されたものではなく、C++ で使用しない場合、コードにバンドルされません。使わないものにお金はかかりません。クラス std::vector、std::list、... はJava/C# の意味での OOP 概念ではありません。それらは、最良の解釈では単なる抽象データ型です。

于 2009-10-30T00:33:09.943 に答える
14

使用しない機能にお金を払わないという C++ の哲学に従っていると思います。プラットフォームによっては、仮想デストラクタを使用することを気にしない場合、仮想テーブルへのポインタは多額の費用がかかる可能性があります。

于 2009-10-30T00:15:51.727 に答える
8

STL コンテナが継承できるように設計されていないのはなぜですか?

私の謙虚な意見では、そうです。そうでない場合、それらは最終的なものにされていました。ソースを調べるstl_vector.hと、STL 実装が保護された継承を使用_Vector_base<_Tp, _Alloc>して、派生クラスへのアクセスを許可していることがわかります。

 template<typename _Tp, typename _Alloc = allocator<_Tp> >
 class vector : protected _Vector_base<_Tp, _Alloc>

サブクラス化が歓迎されない場合、プライベート継承を使用しませんか?


非仮想デストラクタを使用してサブクラス化する標準安全な方法はありますか (新しいメソッドを追加したいだけで、メソッドをオーバーライドしたくないと仮定しましょう)。

protectedまたは継承を使用して、キーワードprivateでインターフェースの必要な部分を公開してみませんか?using

class MyVector : private std::vector<int>
{
     typedef std::vector<int> Parent;

     public:
        using Parent::size;
        using Parent::push_back;
        using Parent::clear;
        //and so on + of course required ctors, dtors and operators.
};

std::vector<int>非仮想デストラクタの唯一の問題は、オブジェクトが親クラスのインスタンスとして削除されたときに派生デストラクタを呼び出さないことであるため、このアプローチにより、クラスのユーザーがインスタンスをアップキャストせず、安全です。

...クラスにデストラクタがない場合でも、パブリックに継承する可能性があるという漠然とした考えもあります。異端?

于 2012-12-14T15:00:22.627 に答える
1

すべてのクラスに盲目的に仮想デストラクタを追加することは想定されていません。その場合、言語は他のオプションを許可しません。他の仮想メソッドを持たないクラスに仮想メソッドを追加すると、ポインタのサイズ (通常は 4 バイト) だけクラス インスタンスのサイズが増加します。内容によっては高額です。仮想メソッドのリストを保持するために v-table が作成され、各インスタンスが v-table へのポインターを必要とするため、サイズの増加が発生します。通常、インスタンスの最初のセルにあります。

于 2009-10-30T20:08:21.730 に答える
0

指摘されているように、STL コンテナーは継承できるように設計されていません。仮想メソッドはなく、すべてのデータ メンバーはプライベートであり、保護されたゲッター/セッター/ヘルパーはありません..そして、あなたが発見したように、仮想デストラクタはありません..

「is-a」ではなく「has-a」の方法で、実装の継承ではなく構成を介してコンテナーを実際に使用することをお勧めします。

于 2009-10-30T10:40:08.367 に答える
-2

クラスが正しくサブクラスになるのを妨げる仮想デストラクタはありません。

于 2009-10-30T00:15:39.437 に答える