2012-04-04 25 views
3

私の質問は少し複雑です:メンバ関数ポインタのマップへの挿入

class a 
{ 
public: 
    a() 
    { 
      pointerMap.insert(pair<std::string, void a::*(int, int)> ("func1", func1); 
      pointerMap.insert(pair<std::string, void a::*(int, int)> ("func2", func2); 
    } 

private: 
    void func1(int a, int b); 
    void func2(int a, int b); 
    std::map<std::string, void a::* (int, int)> pointerMap; 
} 

私の質問があり、これは、メンバ関数へのポインタを追加することについて移動する正しい方法ですオブジェクト内のマップに移動し、個々のインスタンスのfunc1またはfunc2を参照するだけですか?

また、ポインタからこの関数を呼び出す方法についてはわかりません。このようなものでしょうか?

map["func1"](2,4); 

メンバ関数を操作するときの構文について少し混乱します。

+0

少し背景を与えることができますか?このようにクラスを設定する目標は何ですか? – jpm

+0

これはまったくテストしましたか? –

+0

'std :: make_pair(" func1 "、func1)'を使って、あなたのタイプを推論します。 – GManNickG

答えて

7

まず、コード:ご質問のために今

#include <map> 
#include <string> 
class a 
{ 
public: 
    a() 
    { 
     pointerMap["func1"] = &a::func1; 
     pointerMap["func2"] = &a::func2; 
    } 

    void invoke(const std::string& name, int x, int y) { 
     if(pointerMap[name]) 
     (this->*pointerMap[name])(x, y); 
    } 

private: 
    void func1(int a, int b) {}; 
    void func2(int a, int b) {}; 
    std::map<std::string, void (a::*)(int, int)> pointerMap; 
}; 

int main() { 
    a o; 
    o.invoke("func1", 1, 2); 
} 

、:私の質問は

、これは内マップにメンバ関数へのポインタを追加することについて移動する正しい方法ですオブジェクト

サブスクリプト演算子[]は、実行していた挿入よりもはるかに読みやすくなっています。

このようにして、個々のインスタンスのfunc1またはfunc2のみを参照します。

Pointer-to-member-functionにはインスタンスが関連付けられていません。ポインターを呼び出すと、ポインターをインスタンスにバインドします。だから、あなたのマップは静的なメンバーであったかもしれません。

私はポインタからこの関数を呼び出す方法について説明します。

構文は、(instance.*pointer)(args)または(class_pointer->*pointer)(args)のいずれかです。あなたは関数がどのようなインスタンスが呼び出されるべきかを言っていないので、私はthisと仮定しました。あなたのポインタがマップに住んでいるので、我々は持っている:

((this)->*(this->pointerMap["func1"]))(arg1, arg2) 

または

(this->*pointerMap[name])(x, y); 
+0

うわー、これは非常に徹底的に良いです。以前にインデックスを挿入しなくても添え字演算子を使用しても境界外のエラーは発生しないことに気づいていませんでした。したがって、存在しないインデックスに添字演算子を使用すると、マップ内のインデックスが作成されます。 – FatalCatharsis

+0

@FatalCatharsis:はい、デフォルトで初期化された値が作成されます。 (この場合、ヌルポインタです。) – GManNickG

+0

yeh、それはかなりクールです。だから今私がしなければならないのは、それにアクセスする前にその名前のマップインデックスが存在することを確認して、偶然ヌル関数ポインタをチェックするだけです。私の質問などにお返事いただきありがとうございます:P – FatalCatharsis

1

マップへのポインタを挿入する正しい方法ですが、あなたはmake_pairを使って、少し物事を整理することができます。すなわち、あなたのためのテンプレート引数を推論た:

pointerMap.insert(std::make_pair("func1", &func1)); // The '&' is optional 

関数を呼び出すには、Oを依存し、.*または->*演算子を使用する必要がありますn個のオブジェクトかどうかは、ポインタかどうかを介して参照されているそれを呼んでいる:

a obj; // Regular object 
(a .* map["func1")(2, 4); // Extra parens needed due to operator precedence 

a *ptr; // Pointer 
(a ->* map["func1")(2, 4); 

構文ができるので、一部の人々は、何をやっていることがより明確にするためにマクロを定義したいですいくつかに少し混乱します。

#define CALL_MEMBER_FUN_PTR(obj, fun) ((obj) ->* (fun)) 
... 
a *ptr; 
CALL_MEMBER_FUN_PTR(ptr, map["func1"])(2, 4); 
2

これはまさに正しいことです。たぶんtypedefが、物事ビットクリーナーを作ることができます:あなたは絶対にそうでないあなたが悪いのポインタを持っているため、マップアイテムは、に存在することを確認する必要があるので、

typedef std::map<std::string, void(a::*)(int, int)> pfmap_type; 
pfmap_type m;    // ^^^^^^ 

// ... 

m.insert(pfmap_type::value_type("hello", &a::func1)); 
             // ^^^ 

(this->*(m["hello"]))(1, 2); 
(this->*(m.find("hello")->second))(3, 4); 

は実際には、マップ・アクセスのどちらも、良いアイデアです。だから私はこのようなものをお勧めします:

void call(const char * key, int a, int b) const 
{ 
    pfmap_type::const_iterator it = m.find(key); 
    if (it != m.end()) { (this->*(it->second))(a, b); } 
} 
関連する問題