1

読んでくれてありがとう。これは、適切な解決策があるという点で厄介な設計上の質問ですが、私があまり経験していないテンプレートを介したより良い方法がないかどうかという質問です。

保存する必要のある一連のタイプのデータテーブル(抽象クラ​​スDataTableから派生)があります。ベクトルDataTable*を格納し、すべてのDataTableIndexに共通の一般的な作業を処理する「DataTableIndex」抽象クラスを作成しました。ルックアップの実行、必要な場合にのみテーブルが読み込まれるようにするプロキシパターンの実装、エラーチェックなどです。

次に、テーブルタイプごとにサブクラス化します。これを行う必要がある唯一の理由は、テーブルタイプごとに、それをロードするために呼び出される特定の関数があるためです。

DataTableには多くのサブクラスがあるため、可能であれば、テンプレートを介してDataTableIndexのこのサブクラス化を避けたいと思います。

class DataTableIndex
{  
  // various functions to implement lookup, Proxy and error checking
  //   functionality common to all DataTableIndexes.
  // This code needs access to _lookupTable and _theTables

  DataTable* getTable( int tableNum );

private:
  // These functions call the appropriate user interface function for loading
  //   a table of the subclass' type.
  //   They are called by more general non-virtual public functions
  virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable ) = 0;
  virtual DataTable* loadTable( int tableNum ) = 0;

  vector<LookupEntry*> _lookupTable;
  vector<DataTable*>   _theTables;

  UserInterface* UI;
};  

このクラスには非常に単純なサブクラスがあり、基本的には、データテーブルのファイルを実際に開いて解析するユーザーインターフェイスクラスの関数を指します。

class TableTypeA_Index : public DataTableIndex
{
  virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
  {
     return UI->loadTableAIndex( _lookupTable );
  }

  virtual DataTable* loadTable( int tableNum )  
  { 
     return UI->loadTableTypeA( _lookupTable[ tableNum ] );
  }

};

これは適切に機能します。しかし、たとえば「loadTableTypeA」をテンプレートパラメータを介してDataTableIndexに渡すことができるはずなので、サブクラス化する必要はありません。

テンプレートを使用したいもう1つの理由は、DataTable*を常に実際のテーブルタイプにキャストする必要がないことです。コンパイル時にテーブルのタイプを知っていても、dynamic_cast <>を使用してエラーチェックを行う必要があるように感じますが、getTable()の呼び出し元が毎回これを実行する必要はありません(よく呼ばれます)。

私の理想的な解決策は次のとおりです。1)DataTableIndexクラスをテンプレートに一般化し、_lookupTableと_theTablesのLookupEntry*とDataTable*をテンプレートパラメーターで置き換えます。これにより、キャストが不要になります。

2)適切なUI関数をマップして、サブクラス化せずに適切なテーブルタイプをロードします。

だから基本的にはこのクラスを使ってこんな感じにしたいと思います(どういうわけか)

DataTableIndex< LookupEntryTypeAMatlab, 
                TableTypeA, 
                loadTableAIndex(),
                loadTableTypeA() > theTypeAIndex;

ポリシークラスについて考えましたが、そのアプローチの印象は、この場合、サブクラスを別のクラスに移動するだけであるということでした。

4

2 に答える 2

1

一般に、これは戦略パターンを使用して実行できます。これは単純な構成を使用して実装できるため、テンプレートは必要ありません。ただし、異なるテーブルタイプごとに特別な戦略を定義する必要があります。これにはサブクラス化が必要になります。

class LoadTableStrategy {
public:
    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable ) = 0;
    virtual DataTable* loadTable( int tableNum ) = 0;
};

このクラスは、各テーブルタイプのサブクラスである必要があります。DataTableIndex次に、コンストラクターでのインスタンスを受け取り、LoadTableStrategyプライベート仮想関数の代わりにそれを使用してデータをロードします。

もちろん、戦略タイプをテンプレートパラメータとして渡すこともできますが、これは欠点であることに注意してください。DataTableIndex異なるテンプレートパラメータでインスタンス化された2つは、コンパイラの異なるタイプになります。特定のオーバーロードを作成するか、関数自体を関数テンプレートにしない限り、両方を処理できる関数を定義することはできません。

于 2011-03-09T09:40:53.240 に答える
0

テンプレートを使い続けたい場合は、テンプレートに変えることができますがTableTypeA_Index、UserInterfaceのメンバー関数へのポインターをコンストラクターに渡す必要があります。例えば:

typedef bool (UserInterface::*LoadTableIndexFP) (vector<LookupEntry*>&);
typedef DataTable* (UserInterface::*LoadTableTypeFP) (LookupEntry*);

template<class TABLE>
class TableType_Index : public DataTableIndex
{
public:
    TableType_Index (LoadTableIndexFP loadTableIndexFP, LoadTableTypeFP loadTableTypeFP)
        : loadTableIndexFP (loadTableIndexFP)
        , loadTableTypeFP (loadTableTypeFP)
    {
    }

    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
    {
        return (UI->*loadTableIndexFP) (returnLookupTable);
    }

    virtual DataTable* loadTable( int tableNum )
    {
        return (UI->*loadTableTypeFP) (_lookupTable[ tableNum ]);
    }

private:
    LoadTableIndexFP loadTableIndexFP;
    LoadTableTypeFP loadTableTypeFP;
};

int main (int argc, char* argv[])
{
    TableType_Index<TableA> (&UserInterface::loadTableAIndex, &UserInterface::loadTableTypeA);

    return 0;
}

あなたの定義からその役割が何であるかがLookupEntryTypeAMatlab明確でないので、私はテンプレートパラメータとして追加しませんでした。TableTypeA_Index

ptr-to-mem-funsをctorに渡す代わりに、テーブルタイプごとにtraitsクラスを設定することもできます。

template<typename T>
struct TableTraits
{
};

template<>
struct TableTraits<TableA>
{
    static LoadTableIndexFP loadTableIndexFP;
    static LoadTableTypeFP loadTableTypeFP;
};

LoadTableIndexFP TableTraits<TableA>::loadTableIndexFP = &UserInterface::loadTableAIndex;
LoadTableTypeFP TableTraits<TableA>::loadTableTypeFP = &UserInterface::loadTableTypeA;

template<class TABLE>
class TableType_Index : public DataTableIndex
{
public:
    virtual bool loadIndex( vector<LookupEntry*>& returnLookupTable )
    {
        return (UI->*TableTraits<TableA>::loadTableIndexFP) (returnLookupTable);
    }

    virtual DataTable* loadTable( int tableNum )
    {
        return (UI->*TableTraits<TableA>::loadTableTypeFP) (_lookupTable[ tableNum ]);
    }
};

しかし、どちらのアプローチも理想的ではありません...

于 2011-03-09T18:45:11.947 に答える