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++ 代码行之一。:-)

在一个完全不相关的说明中,因为您使用的是 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++ 虚函数工作不需要字符串比较。

成员函数指针有一些用例。这种情况不是其中之一。特别是因为它掩盖了代码的意图。(请记住,代码是供人类阅读的!)

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 回答