13

テンプレートのダックタイピングと純粋な仮想基本クラスの継承のどちらかを選択するためのガイドラインはどれですか?例:

// templates
class duck {
    void sing() { std::cout << "quack\n"; }
};

template<typename bird>
void somefunc(const bird& b) {
    b.sing();
}

// pure virtual base class
class bird {
    virtual void sing() = 0;
};

class duck : public bird {
    void sing() { std::cout << "quack\n"; }
}

void somefunc(const bird& b) {
    b.sing();
}
4

5 に答える 5

12

テンプレートのダックタイピングでは、静的なポリモーフィズムを実行しています。したがって、あなたは次のようなことをすることはできません

std::vector<bird*> birds;
birds.push_back(new duck());

ただし、コンパイル時の型指定に依存しているため、もう少し効率的です(仮想呼び出しがないということは、動的ディスパッチがないことを意味します(動的型に基づく))。

于 2010-07-23T16:25:06.730 に答える
3

物事の「テンプレートの性質」を広く伝播させることが問題ない場合は、テンプレート(「コンパイル時のダックタイピング」)を使用すると、(仮想関数呼び出しに暗黙的に含まれる「間接性のレベル」を回避して)驚異的な速度を得ることができます。メモリフットプリントにいくらかのコストがかかります(理論的には、優れたC ++実装は、テンプレートに関連するメモリオーバーヘッドを回避できますが、このような高品質のコンパイラが、移植が必要なすべてのプラットフォームで必ずしも利用できるとは思えません。 )。したがって、少なくとも実用的には、速度とメモリのトレードオフのようなものです。実行している操作がI/Oのように非常に遅い場合は、仮想呼び出しを回避することによる比較的小さな速度の向上は、ユースケースにとって実際には重要ではない可能性があります。

于 2010-07-23T16:25:57.167 に答える
2

コンパイル時間とランタイム。コンパイル時のバインディングが必要な場合は、テンプレートを使用する必要があります。コンパイル時に型がわからない場合は、仮想継承を使用する必要があります。

于 2010-07-23T18:52:26.500 に答える
0

それらは2つの完全に異なるものです。一方は他方に代わるものではありません。テンプレート関数は、somefunc()鳥だけでなく、タイプのクラス全体に適用される一般的な操作を提供します。そのパラメータのタイプは、コンパイル時に認識されている必要があります。仮想メソッドは、鳥に固有の実行時ポリモーフィック操作を提供します。パラメータの正確なタイプ(this)は、コンパイル時に知る必要はありません。

それらは異なる機能を提供し、互いに競合しないため、2つのアプローチのどちらかを決定する必要があることはめったにありません。必要な機能を決定すれば、賢明なアプローチが明らかになります。それは2つの組み合わせでさえあるかもしれません。

(ところで、ここでは「ダックタイピング」という用語が誤用されています。どちらのアプローチもダックタイピングではありません。C++レキシコンからフレーズを削除する必要があります。)

于 2010-07-23T17:25:12.587 に答える
-2

@ジョンは正しいです。選択の余地がない2つの共変型パラメーターがある場合は、テンプレートを使用する必要があります。オブジェクト指向の手法は実行時のディスパッチを提供しますが、メソッドが最大で1つのバリアント引数(オブジェクト)を持つタイプでのみ使用できます。

最も興味深い問題は、N-aryでN> 1の関係に関係しているため、通常はテンプレートを使用する以外に選択肢はありません。標準ライブラリを調べて、どの手法が最も使用されているかを確認してください。

于 2010-11-28T03:34:27.610 に答える