2

テンプレートを使用するときにポリモーフィズムを使用することは可能ですか?

たとえば、「フィルター」というクラスがあり、データをフィルター処理する方法についてさまざまなバリエーション/クラスがあるため、テンプレートに基づいてオブジェクトを初期化します (メインで定義されているフィルターのタイプ)

#include "Filter1.h"
#include "Filter2.h"
template<typename T>
class Filters {

public:

    void Filter(vector<double> &vec) {

        T type;

        type.Filter(vec);
    }
};


// class Filter1
class Filter1 {
   public:

      void Filter(vector<double> &vec) {

         // Code for "Filter1"

      }
};

// MAIN

int main() {
   vector<double> sample; // this is a sample vector
   Filters<Filter1> exam1;
   exam1.filter(sample);
}

これは機能しますが、"Filter2" では、渡すパラメーターがさらにあるとします。

 class Filter2 {

  public:
     void Filter(vector<double> &vec, double point)
     {
         // Filter 2
     }        
 };

そして、メイン:

int main()
{
    vector<double> sample;
    double point = 9;

    Filters<Filter2> exam;
    exam.Filter(sample, point);
}

「フィルター」の「フィルター」は 1 つのパラメーターしか受け入れないため、これは機能しません。

私が抱えている問題は、フィルターが受け入れるパラメーターが異なるという事実です。たとえば、「Filter1」は 2D ベクトルと double を通過しますが、このクラスの Filter メソッド定義は 1D ベクトルのみを受け入れます。

私は(理論的には)さまざまなクラスを初期化するスイッチステートメント(「T」)を使用できると考えていました。

任意のアイデアをいただければ幸いです。

4

2 に答える 2

1

テンプレートを使用してジェネリック プログラミングを行う場合は、インターフェイスに対してコーディングする必要があります。ここでは、この用語の OOP の意味を使用していません。代わりに、より広い意味です。

例として、Random-Access Iterator の概念に似たインターフェイスに対してコーディングする関数テンプレートを次に示します。

template<typename It>
typename std::iterator_traits<It>::value_type
sum(It first, It last)
{
    typedef typename std::iterator_traits<It>::difference_type diff_t;
    diff_t const size = last - first;

    typename std::iterator_traits<It>::value_type accum = 0;
    for(diff_t i = 0; i != size; ++i) {
        accum += first[i];
    }

    return accum;
}

(もちろん、この例は偽物です。ここでの意図は、複数のランダム アクセス イテレータ操作を示すことです。)

コントラクトでItRandom-Access Iterator を指定しているため、次のものにアクセスできることがわかっsumています。

  • メンバー型std::iterator_traits<It>::value_typeおよび、それぞれおよびstd::iterator_traits<It>::difference_typeの結果から初期化できる型ですoperator[]operator-
  • Itlikeoperator-およびの操作。双方向イテレータoperator[]などでは使用できません。

そのため、 、 、および とsum一緒に使用できます。これらはすべて異なるタイプであり、いくつかの側面で異なる場合がありますが、少なくともすべてランダム アクセス イテレータの概念のモデルです。std::vector<int>::iteratorstd::deque<double>::const_iteratorlong*

0(観察者は、and+=を使用することで、コントラクトで がvalue_type算術のような型であることを要求していることに気付くでしょう。これもまた、コーディング対象のインターフェイスです!)

Filters次に、明らかに として使用する予定の を設計するときは、 が満たす必要Filters<FilterLike>がある一般的な最小限のインターフェイスは何かを自問する必要がありますFilterLikeFilterXおそらくいくつかの操作を除いてほとんどのものがある場合はFilterLike、いくつかのオプションがあります。

  • あなたの質問で言及したように、Filtersその特定の操作を使用する場所はどこでも、FilterX特別に処理されるように特別なケースにすることができます-これはおそらくあなたができる最悪のことです。操作が必要なすべてのサイトで実行する必要があるという点で脆弱です (現在は 1 つだけのように見えても、将来はどうなるでしょうか?)。いいえ、クラステンプレート関数メンバーの関数本体内で型をオンにできないという点で不便です(冗長で明白でないさまざまな手法を使用する必要があります)。Filtersそして、知っておく必要がある結合を導入しますFilterX-なぜそれを気にする必要があるのでしょうか?

  • の明示的な特殊化を記述しFilters<FilterX>ます。FilterXこれは上記とよく似ていますが、1 つまたは 2 つの操作だけが異なる場合は興味深いオプションです。前のソリューションとは異なり、これはプライマリ テンプレートがそのまま残され、FilterX特定のものはすべて同じ場所に配置されるため、脆弱ではありません。一方、 の半分がFilterX既に のように動作している場合は、 のコードの半分が重複しているか、 と の間の共通コードをリファクタリングするために追加の作業が必要でFilterあることを意味するに違いありません。したがって、結合の量はさまざまです。プライマリ テンプレートがこの明示的な特殊化について知る必要がない場合、それは適切なオプションであり、明示的な特殊化をプライマリ テンプレートにバンドルする必要さえありません。Filters<FilterLike>Filters<Filter>Filters<FilterX>

  • AdaptedFilterXインターフェイスのモデルであるan を作成し、FilterLikeそのすべての操作を基になる に転送しますFilterX。いくつかFilterXのがありFilterY、それらはすべて のほぼモデルですFilterが、共通のインターフェースを持っています。AdaptedFilter<FilterX>ある意味で、AdaptedFilterテンプレートは a のモデルを a のモデルに「変換」しますFilterXLikeFilterLike

余談ですが、C++11 を使用している場合は、 withFilterを構築するために任意の引数を受け入れるように記述できます。FilterLike

template<typename... Args>
void Filter(Args&&... args)
{
    FilterLike filter(std::forward<Args>(args)...);
    // go on using filter...
}

ただし、単に受け入れる方がおそらく簡単です(C ++ 03で機能します)FilterLike

void Filter(FilterLike filter)
{
   // go on using filter...
}
于 2012-12-01T19:12:25.797 に答える
1

テンプレートに依存している場合、別の方法は、そのテンプレートを引数としてフィルターを渡すことです。ほとんどのフィルターは、+ - / などの標準操作に依存しています。したがって、Vector2D、Vector1D ... クラスでその関数をオーバーロードすることができ、フィルター関数はそのメソッドを自動的に呼び出します。

これが少し役立つことを願っています:)

于 2012-12-01T18:14:05.297 に答える