シナリオ (参照用に以下のコードを参照):
- 元の (ベース) 実装には、リストを返す func1() が必要です。内部的には、マージとスプライスを呼び出します。
- 後続の (派生) 実装には、ベクトルを返す func1() が必要です。ランダムアクセスが必要です。
func2() は両方の実装に共通であり、単純に前方反復子が必要です。
#include <iostream> #include <list> #include <vector> class Base { protected: virtual void func1(std::list<int>& l /* out parameter */) { // This must use list. Calls merge and splice. std::cout << "list version of func1 in base\n"; } virtual void func1(std::vector<int>& v) { // This should never be called, but code won't compile without it. std::cout << "vector version of func1 in base\n"; } template <class T> void func2(T container) { typename T::const_iterator it = container.cbegin(); // Iterate and perform work. Common to both Base and Derived. std::cout << "func2 in base\n"; } template <class T> void processHelper() { T container; func1(container); func2<T>(container); } public: virtual void process() { processHelper<std::list<int> >(); } }; class Derived : public Base { protected: virtual void func1(std::vector<int>& v /* out parameter */) { // This must use a random access container. std::cout << "Vector version of func1 in derived\n"; } public: virtual void process() { processHelper<std::vector<int> >(); } }; int main(int argc, const char * argv[]) { std::vector<int> var; Derived der; der.process(); //std::list<int> var; //Base bs; //bs.process(); std::cout << "done\n"; }
目標:
- コードの複製 (カット アンド ペースト) がない (または最小限)。
- Boost でのコンパイルは避けてください。(まだ必要ではありません。これは必要ありません。)これにより、いくつかの any_iterator 実装が除外されます。
質問:
私がやっていることを達成するために C++ でより良い OO 設計はありますか? func1() から戻る前に、リストをベクターに変換したくない、またはその逆をしたくない理由があります。具体的には、この時点ではリストが大きいため、余分なコピーが発生しないようにしたいと考えています。opaque_iterator http://www.mr-edd.co.uk/code/opqitを返すように func1() を設計することもできましたが、不明なヘッダー ファイルを取り込むことをためらっていました。
いずれにせよ、この問題は独自のアカデミック ライフを帯びていました。この問題は、Java ではコレクションが共通のインターフェースを実装しているため非常に簡単ですが、C++ では難しいようです。この関数を呼び出す実行パスがないにもかかわらず、コードをコンパイルするためだけに Base::func1(std::vector& v) を実装しなければならないという醜さに特に悩まされています。もっと簡単な方法があることを願っていますが、もっと簡単な解決策は見当たりません。