2009-03-10 9 views
8

文字列をインスタンスメンバ関数にマップし、各マッピングをマップに格納したいと考えています。マップ内のメンバ関数へのポインタを格納

このようなことを行うにはどうすればよいですか?

class MyClass 
{ 
    //........ 
    virtual double GetX(); 
    virtual double GetSomethingElse(); 
    virtual double GetT(); 
    virtual double GetRR(); 
    //........ 
}; 


class Processor 
{ 
private: 
     typedef double (MyClass::*MemFuncGetter)(); 
     static map<std::string, MemFuncGetter> descrToFuncMap; 

public: 
     static void Initialize(); 
     void Process(Myclass m, string); 
}; 

void Processor::Initialize() 
{ 

    descrToFuncMap["X"]=&MyClass::GetX; 
    descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
    descrToFuncMap["RR"]=&MyClass::GetRR; 
    descrToFuncMap["T"]=&MyClass::GetT; 
}; 
void Processor::Process(MyClass ms, const std::string& key) 
{ 
    map<std::string, Getter>::iterator found=descrToFuncMap.find(key); 
    if(found!=descrToFuncMap.end()) 
    { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
     } 
} 

この方法に問題があるかどうか、それに共通するイディオムは何か教えてください。代わりにfuncをポインタ

の混乱マップのIは、メンバ関数の数が限られていることを考えると声明チェーンは、ところで、私は役に立つの一部を発見したかもしれ

、私は場合のif-else-使用する必要があります情報ここc++-faq-lite

+0

実際には、マップはif-elseチェーンよりも優れていると思います。必要に応じて、他のメタ情報を後で格納するための素晴らしいフックを提供します。関数ポインタから関数ポインタを含む構造体に値の型を加え、必要な情報を追加します。 –

+0

私は同意して、よく見えますが、経験の浅い開発者にとっては理解しにくいです。 –

答えて

6

私にはうまく見えますが、descrToFuncMapは、静的関数Initialize()の内部から初期化する場合はstaticと宣言する必要があります。

Initialize()が呼び出され、一度だけ呼び出されるようにしたい場合は、シングルトンパターンを使用できます。基本的には、マルチスレッドを行っていない場合は、Initialize()を呼び出す専用のコンストラクタを使用して、descrToFuncMapを独自のクラス(つまりFuncMap)にラップすることを意味します。次にstaticタイプのローカル変数FuncMapProcessor::Process()に追加します。これは変数がstaticであるため継続され、1回だけ初期化されます。

例コード(私は今friendはここで本当に必要ではないことを認識):

class Processor { 
private: 
    typedef double (MyClass::*MemFuncGetter)(); 

    class FuncMap { 
    public: 
     FuncMap() { 
      descrToFuncMap["X"]=&MyClass::GetX; 
      descrToFuncMap["SomethingElse"]=&MyClass::GetSomethingElse; 
      descrToFuncMap["RR"]=&MyClass::GetRR; 
      descrToFuncMap["T"]=&MyClass::GetT; 
     } 

     // Of course you could encapsulate this, but its hardly worth 
     // the bother since the whole class is private anyway. 
     map<std::string, MemFuncGetter> descrToFuncMap; 
    }; 

public: 
    void Process(Myclass m, string); 
}; 

void Processor::Process(MyClass ms, const std::string& key) { 
    static FuncMap fm;  // Only gets initialised on first call 
    map<std::string, Getter>::iterator found=fm.descrToFuncMap.find(key); 
    if(found!=fm.descrToFuncMap.end()) { 
     MemFuncGetter memFunc=found->second; 
     double dResult=(ms).*memFunc();  
     std::cout<<"Command="<<key<<", and result="<<result<<std::end;  
    } 
} 

異なる機能がFuncMapの独自の、別々のインスタンスを作成することができ、これが「真」Singletonパターンではなく、それはあなたが必要とするもので十分です。 "true"シングルトンの場合、FuncMapのコンストラクタをプライベートとして宣言し、という静的メソッドを追加します。このメソッドは、1つだけのインスタンスをstatic変数として定義し、その参照を返します。 Processor::Process()は、あなたは関数ポインタのマップを使用している場合は、「仮想」の使用は避けてください

FuncMap& fm = FuncMap::getInstance(); 
+0

これは静的(固定)です。私は私的な友達クラスの考えが好きです。例を挙げてそれを実証しますか?ありがとう –

0

で私は

void Processor::Process(const MyClass& ms, const std::string& key) 
01に

void Processor::Process(MyClass ms, std::string key) 

を変更したいです

現在、悪影響はありません。おそらくboost :: functionをマップ値として使用すると、将来的にはより簡単になります。

+0

まあまあ、明らかに私はリファレンスとしてconstとして文字列を渡すでしょう。私の質問はおそらく、私はfuncポインタの混乱したマップの代わりにメンバー関数の数が限られているので、if-statementチェーンを使うべきです。 –

+0

マップは私にとっては大丈夫です。 –

0

でこれを使用します。このコンテキストでは、 'virtual'キーワードを使用することはあまり役に立ちません。例えば

descrToFuncMap["X"]=&MyClass::GetX; 

は常に 'のMyClass :: GETX' GETXは、MyClassのの派生クラスによってオーバーライドされる場合でも、関数を呼び出します。

通常、マップを使用するのではなく、単純な構造体配列を作成してforループを使用して、クラス内に多数の関数を持つことはありません。関数の数が少ない場合は、マップと配列のパフォーマンスに大きな違いはありません。以下のコードに類似したものが動作します

class MyClass 
{ 
    //........ 
    double GetX(); 
    double GetSomethingElse(); 
    double GetT(); 
    double GetRR(); 
    //........ 
}; 

typedef double (MyClass::*MemFuncGetter)(); 

struct FuncTable 
{ 
    const char* m_pFuncName; 
    MemFuncGetter m_pFuncPtr; 
}; 

class Processor 
{   
public: 
     void Process(Myclass& m, string); 
}; 

static FuncTable descrToFuncMap[] 
{ 
    { "X", &MyClass::GetX}, 
    { "SomethingElse", &MyClass::GetSomethingElse }, 
    { "RR", &MyClass::GetRR}, 
    { "T", &MyClass::GetT} 
}; 

void Processor::Process(MyClass& ms, const std::string& key) 
{ 
    int functablesize = sizeof(descrToFuncMap)/sizeof(descrToFuncMap[0]) 

    for(int i=0; i< functablesize; ++i) 
    { 
     if(strcmp(key.c_str(), descrToFuncMap[i].m_pFuncName)==0) 
     { 
      MemFuncGetter memFunc=descrToFuncMap[i].m_pFuncPtr; 
      double dResult=(ms).*memFunc();  
      std::cout<<"Command="<<key<<"result="<<result<<std::end; 
      break; 
     } 
    }  
} 
+0

なぜそれはオーバーライドされた関数を呼び出さないのですか? –

関連する問題