2009-07-22 10 views
33

一般化と多型に関する決定を下す必要があります。C++標準の練習:仮想インターフェイスのクラスとテンプレート

まあシナリオは標準です:私はモノリシックな相互依存性のある コードをよりモジュラーでクリーンで拡張性のあるものにしたいと考えています。 デザイン原則の変更が可能な段階ですが、 と私はそれを見ると非常に望ましいです。

純粋に仮想ベースクラス(インターフェイス)またはテンプレートを紹介しますか?

は、私は、テンプレートオプションについての基本を知っています: 少ない間接、より優れた性能は、より多くのように が、無遅延バインディング 、およびコンパイル。

stlは継承をあまり使用しないか、または昇格しません。 しかし、私はそれらがプログラマーによってコードの2行を すべて使用される本当に小さな基本的なツールであることを目指していると思います。

プラグインスタイルのコードと機能の交換が可能であること、 更新可能など、デプロイメント後または実行時にプラグインスタイルがより賢明であると考えています。

まあ、私のシナリオは多少の間にあります。

実行時にコードを交換する必要はありません。コンパイル時に問題はありません。 通常、非常に中心的で頻繁に使用される機能でもあり、 は大きなブロックに論理的に分離できません。

これにより、テンプレートの解決に多少時間を費やすことができます。 私にとっては、ややきれいに見えます。

大きな悪影響はありますか?まだインターフェイスはありますか? どうすればいいですか?彼らはいつですか? これは標準的なC++スタイルをより遵守していますか?

私はこれが主観的に接していることを知っていますが、私は本当に興味があります いくつかの経験。私はスコットマイヤー効果的なCのコピーを持っていません 私はあなたの人に私の希望を設定しました:)

答えて

20

あなたは基本的に正しく、動的多形性(継承、仮想)は、 (例えば、プラグインのアーキテクチャでは)実行時に変更することができます。型がコンパイル時に変更される必要がある場合は、静的多型(テンプレート)を使用することをお勧めします。

テンプレートの潜在的な欠点は、1)一般的にヘッダーに定義する必要があることです(コードが#includeされることを意味します)。これはしばしばコンパイル時間の短縮につながります。

しかし、設計上は可能な限りテンプレートを使用する際に問題はありません。

これは、標準C++ スタイルに準拠していますか?

"標準C++スタイル"に依存します。 C++の標準ライブラリは、すべてのものを使います。STLはすべてのテンプレートを使用していますが、若干古いIOStreamsライブラリは継承と仮想関数を使用していますが、Cから継承されたライブラリ関数はどちらも使用していません。

最近、テンプレートが最も一般的な選択ですが、これは最も標準的なアプローチです。

+3

私は、インターフェイスではなくテンプレートを使用して1つの問題を見ています。要件は完全に暗黙的です。純粋仮想関数を実装する必要がある場合、その正確な署名が与えられます。しかし、_AllocTやIterのようなテンプレートタイプを見ると、あなたのクラスに必要なものや、クラスでなければならないことは分かりません。唯一の知るべき唯一の方法は、それについてのまともなドキュメントを探すことです。私は今日、自分自身のstl互換のアロケータクラスを作成しようとしているときに問題を抱えていました。 – Virus721

+3

"知っているだけのことは、まともなドキュメントを探すことです" - あるいは、コンパイラがどの関数を見つけることができないと不平を言ってコンパイルしようとしているのかを見てみましょう。また、概念はこの問題を解決するためのものです。 (そして、たとえそれがインターフェースだったとしても、まともな文書を見つける必要があるでしょう。上書きする関数を知るだけでは不十分です。また、セマンティクスがどのようなものであるべきかを知る必要があり、インターフェースはそれをあなたに伝えません)。それでも、あなたは正しいです。言語が両方をサポートする理由があります。 :) – jalf

8

これは偽りの反対です。はい、継承と仮想関数の主な用途はiostreamsです。これは非常に古く、stdライブラリの残りの部分とはまったく異なるスタイルで書かれています。

しかし、ブーストのような最新のC++ライブラリの多くは、実行時のポリモーフィズムを利用しているため、テンプレートを使用するだけで使いやすくなっています。

boost::anyおよびstd::tr1::function(以前はboostからも)は良い例である。

コンパイル時に具体的な型が不明なものに対しては、両方とも単一項目のコンテナです(これは、値を取得するための独自の種類の動的キャスト演算子を持っているため、特にanyで明らかです)。古典的なオブジェクト指向の多型の

+0

+1あなたの答えは非常に啓発されましたが、質問に応じて私はjalfのアドバイスを受け入れました。ありがとう。 – AndreasT

9

プロパティ:

  • オブジェクトは実行時にバインドされています。これはより柔軟性がありますが、実行時にもっと多くのリソース(CPU)を消費します
  • 厳しいタイピングは型の安全性を幾分向上させますが、dynamic_castの必要性とそれが顧客の顔に爆発する可能性は簡単に補うことができます

    • コンパイル時バインディングは、より積極的なoptimizatすることができます:
    • おそらくより広く知られており、理解したが、
    • は「古典的な」深い継承階層は、テンプレートによって私にはコンパイル時のポリモーフィズムの

    プロパティを恐ろしいように見えますイオンが、実行時には、柔軟性

  • ダックタイピングがより厄介に思えるかもしれないが、障害がコンパイル時通常されている防ぐ障害
  • 時々読んで理解することが難しくなることができます。コンセプトがないとコンパイラの診断が時々怒りを浮かべることがあります

いずれかを決定する必要はありません。あなたは自由に混在させることができます(そして多くの他のイディオムやパラダイム)。しばしば、これは非常に印象的な(そして表現力豊かな)コードにつながります。 (例えば、タイプ消去のようなものを参照してください。)パラダイムを巧みに混ぜることによって可能なことを知るには、Alexandrescuの "Modern C++ Design"を参照してください。

+0

OOPでの厳密な型指定ですか?それは意味をなさない。コンパイル時の多形性から、すべての型安全性の利点が得られます。 OOPでは、消去(たとえば、実際のタイプをインターフェースの背後に隠すなど)を入力し、アップ/ダウンキャストは、タイプセーフティーのための希望をほとんど排除します。 – jalf

+2

あなたは確かに正しいです。しかし、私が意図したことは、実行時の多態性では、インターフェイスの意図的な実装であることを確信できます。コンパイル時の多態型でのダックタイピングは、偶発的な一致を受け入れる可能性があります。 これはどのように優れていますか? – sbi

0

私の視点から見ると、それはあなたが今まで最高のものです。 OOとのより多くの経験がある場合は、OOを使用してください。ジェネリック医薬品の経験が豊富であれば、ジェネリック薬を使用してください。

どちらのテクニックも、使用できる多くのものを意味するいくつかの同等のパターンを持っています。 OOにおけるEG戦略とジェネリックでのポリシー対OOにおけるテンプレート方法との間の比較。

既に機能しているリファクタリング・プロダクション・コードを計画していても、構造が少し臭いものです。1年か2年後にこの技法を理解すれば、コードをどのようにリファクタリングしたかを後悔する可能性があるため、新しい設計技法を試すには言い訳として使用しないでください。テクニックを習得しているときに、新しい柔軟性を導入するのはとても簡単です。テクニックに熟練していない場合は、既存のコードのデザインを改善することが目的です。コード内に大きな陰茎のシンボルを作成するのではなく、デザインを改善する方法を知っていますか?

個人的に私は理解しやすく、ほとんどの人が変えることができるきれいなデザインを作り出すことができることを知っているので、OOでより優れており、それを好む傾向があります。最も一般的なコードは、イテレータやアルゴリズムのジェネリック関数の作成など、他のジェネリックコードとのインタフェースを目指しています。

4

私のプレートに少しより多くの経験をシャベルた後、私は好きではないテンプレート内のいくつかのものがあります。 使用可能な言語であることから、テンプレートメタプログラミングを失格いくつかの欠点があります。

  • は、読みやすさ:あまりにも多くのブラケット、あまりにも多くの非言語施行(したがって、誤用)規則のプログラミング言語で通常の進化を受けて誰かのため
  • 、テンプレートがある読めないウント不可解
  • 時にはそれは試してみました誰かのように感じている(ちょうどブーストBGLを見て) 〜にawkのC++コードジェネレータを使用します。
  • コンパイラのエラーメッセージは、基本的な "言語"のような機能を得るには、あまりにも多くのハックが必要です(ほとんどがC++ 0xで修正されました)
  • 実装ファイル内にテンプレートはありません。ヘッダーのみのライブラリ(非常に両側の剣です)
  • 通常のIDEのコード補完機能は、テンプレートであまり役に立ちません。
  • MPLで大きなことをやっているのが "不毛な"ようだが、別の言葉を見つけることができない。テンプレート化されたコードのすべての行は、そのテンプレート型の制約を生成します。これは、テキスト置換型の方法で強制されます。継承階層には本質的な意味がありますが、テンプレート構造には何もありません。それはすべてが空であるようです*とコンパイラは、segfaultがあるかどうかをあなたに伝えようとします。

これらのことはすべて、基本的なユーティリティとライブラリでかなりうまく使用しています。高水準の機能やハードウェアに関連するものを書くことは、私のためにそれをカットしていないようです。 意味私は私のビルディングブロックをテンプレートしますが、家を古典的な方法でビルドします。

0

私は大きなコードベースで両方を使用します。型がコンパイル時にわかっているときは、テンプレートで設計します。実行時にしかわからないときは、仮想関数を使用します。仮想関数はプログラミングが簡単で後で読むのが簡単だが、パフォーマンスが重要な時代であり、テンプレート多形性(実際に多形性と呼べる場合)がインライン化できるという事実が本当に役立ちます。

関連する問題