Указатели на функции-члены C ++ - PullRequest
3 голосов
/ 08 февраля 2012

Я делаю небольшую игру на 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();

    [...]
}

Не могли бы вы дать мне хороший совет о правильном способе их реализации?

С уважением.

Ответы [ 2 ]

5 голосов
/ 08 февраля 2012

Я думаю, что строка, которую вы ищете -

(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)();
};

Надеюсь, это поможет!

3 голосов
/ 08 февраля 2012

Правильный способ программирования в этом случае состоит в том, чтобы прекратить программировать как C на C ++ и начать использовать функции C ++, такие как виртуальные функции. : -Р

Я говорю «программирование как 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);
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...