3

私は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();

    [...]
}

それらを実装する正しい方法について、良いアドバイスをいただけますか?

よろしくお願いします。

4

2 に答える 2

5

あなたが探しているラインは

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

これを分析しましょう。まず、実際のメンバー関数ポインターに到達する必要があります。

spawn->ptr

ここでspawnはポインタなので、フィールド->を選択するために使用する必要がありptrます。

それができたら、メンバー選択へのポインター演算子を使用してent、適切なメンバー関数を選択するように指示する必要があります。

ent->*(spawn->ptr)

最後に、関数を呼び出すには、このメンバー関数を呼び出すように C++ に指示する必要があります。C++ の演算子の優先順位の問題により、最初にメンバー関数に評価される式全体を括弧で囲む必要があるため、次のようになります。

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

それだけの価値はありますが、これは私が最近見た中で最も奇妙な C++ コード行の 1 つです。:-)

まったく関係のないことですが、あなたは C++ を使用しているため、typedef struct. 言うだけ

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

お役に立てれば!

于 2012-02-08T06:07:12.977 に答える
3

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

私が「C のようなプログラミング」と言うのは、あなたがやっていることは、C プログラマーが 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);
};
于 2012-02-08T06:10:40.527 に答える