2012-02-08 32 views
3

私はC++で少しゲームをしています。クラスメンバ関数のポインタを発見しています。 私はそれらを正しい方法で動作させる考えはありませんが、私の試みです。C++メンバ関数ポインタ

// A struct where the function pointer will be stored for the call 
// By the way, is there a way to do the same thing with classes ? 
// or are structs still fine in C++ ? (Feels like using char instead of string) 
typedef struct  s_dEntitySpawn 
{ 
    std::string  name; 
    void   (dEntity::*ptr)(); 
} t_dEntitySpawn; 

// Filling the struct, if the entity's classname is "actor_basicnpc", 
// then I would like to do a call like ent->spawnBasicNPC 
t_dEntitySpawn  dEntitySpawns[] = { 
    { "actor_basicnpc", &dEntity::spawnBasicNPC }, 
    { 0, 0 } 
}; 

// This is where each entity is analyzed 
// and where I call the function pointer 
void   dEntitiesManager::spawnEntities() 
{ 
    dEntity  *ent; 
    t_dEntitySpawn *spawn; 

    [...] 

     // It makes an error here, feels very weird for me 
     if (!spawn->name.compare(ent->getClassname())) 
     ent->*spawn.ptr(); 

    [...] 
} 

私はそれらを実装する正しい方法について教えてください。

よろしくお願いいたします。

+1

代わりにインターフェイスを使用してください。つまり仮想メソッドを持つ基本クラスを作成し、そのメソッドの適切な実装でさまざまなクラスを作成します。コードを読みやすくし、必要に応じて動作させます。 –

+0

[クラスデータメンバのときにメンバ関数へのポインタを呼び出す方法は?](http:// stackoverflow。com/questions/6316751/invoke-pointer-to-member-function-when-a-class-data-member) – iammilind

+1

他の人が簡単に理解できるように、良い命名スタイルを使用することを強くお勧めしますあなたは正しい答えを –

答えて

5

私は、あなたが探している行が

(ent->*(spawn->ptr))(); 

のは、これを解剖してみましょうだと思います。まず、我々は、ここでは、spawnがポインタである、と私たちはptrフィールドを選択し->を使用する必要があるので

spawn->ptr 

あり、実際のメンバ関数ポインタに取得する必要があります。

我々は、我々は適切なメンバ関数を選択するようにentを伝えるためにへのポインタメンバー選択演算子を使用する必要があることをしたら:

ent->*(spawn->ptr) 

は最後に、関数を呼び出すために、我々は指示する必要がありますC++でこのメンバ関数を呼び出します。 C++での演算子の優先順位の問題のために、あなたは最初のメンバー関数に評価される式全体を括弧しなければならないので、我々は何が価値があるため

(ent->*(spawn->ptr))(); 

を持っている、これはC++コードの奇妙なラインの一つであるIしばらく見てきました。 :-)

C++を使用しているため、全く関係のないメモでは、私はtypedef structを使用しないでください。ちょうど

struct t_dEntitySpawn { 
    std::string name; 
    void (dEntity::*ptr)(); 
}; 

希望するといいですよね。

+0

+1します。しかし、この質問は私の前の質問と重複しています。 – iammilind

+0

ありがとう!これはもっと明確になりました、私は本当に理解して、良い一日を! –

3

この場合、正しい方法はC++のCのようなプログラミングをやめ、仮想関数のようなC++の機能を使い始めることです。 :-P

CプログラマがどのようにC言語でpolymorphismを実装するかと似ているので、私は「Cのようなプログラミング」と言います。 C++には、あなたの状況を解決するために設計された多態性のサポートが組み込まれているので、C++で行う必要はありません。仮想関数は、C++が多態性を実装する方法です。

この場合、関数ポインタによる多態性は、C++仮想関数が動作するために文字列の比較が必要ないため、現在のものよりもはるかに高速になる可能性があります。

メンバー関数ポインタの使用例があります。この状況はその1つではありません。特に、あなたのコードの意図を覆してしまうからです。 (人間が読むことができるコードはあります)。

class EntitySpawn 
{ 
public: 
    void spawn_entity() 
    { 
     spawn(); 
    } 

private: 
    // std::string name; // Not necessary for polymorphism to work 
    virtual void spawn() = 0; 
}; 

class ActorBasicNPC : public EntitySpawn 
{ 
private: 
    virtual void spawn() { /* implementation specific to ActorBasicNPC */ } 
}; 

void test_spawn(EntitySpawn& es) 
{ 
    // This will call the correct implementation of spawn(), 
    // even though we only got a reference to an EntitySpawn. 
    es.spawn_entity(); 
} 

int main() 
{ 
    ActorBasicNPC npc; 
    // Calls ActorBasicNPC::spawn() even though only a 
    // reference to EntitySpawn was passed. 
    test_spawn(npc); 
}; 
+0

+1これを行う正しい方法を与えるための+1。 – templatetypedef

+0

本当にありがとう、私はこれを整理するためのより良い方法としてはっきりと見て、私はバーチャルを完全に忘れてしまったし、それはC + +言語の方が適していると感じています。 –

+0

+1右。私たちはかなり工場のパターンに従っています。ファクトリを使用するには、ファクトリを使用する前にファクトリのインスタンス(つまり、EntitySpawnを実装するインスタンス)が必要です。エンティティのリストを生成するファクトリのリストを管理する上で害はありません。 –

関連する問題