C ++: определение типа объекта - PullRequest
4 голосов
/ 22 июня 2011

Мне любопытно, какие конструкции или языковые возможности, доступные как в текущем C ++, так и в C ++ 11, могут использоваться для определения типа объекта.Пример:

class Base {
};

class DerivA
    : public Base {
};

class DerivB
    : public Base {
};

void foo(Base* obj) {
    // Identify if `obj` is a `DerivA` or a `DerivB`
}

Это упрощение.Казалось бы, вместо того, чтобы иметь способ идентифицировать тип, лучшее решение состоит в том, чтобы перегрузить функцию для двух производных типов и покончить с базовым классом.

Мой реальный вариант использования - один, гдеодин класс не интересуется точным типом объекта (т.е. просто нуждается в реализации Base), а другой класс должен точно знать, какую реализацию Base использует первый класс.

Этопроисходит в системе игровых объектов на основе компонентов.База будет EntityState, а ее производные типы будут StandingState, DeadState и т. Д. Класс Entity - это тот, который нуждается только в общем объекте EntityState, а класс EntityRepresentation должен точно знать, в каком состояниисущность должна решить, рисовать ли «стоячую» анимацию или «мертвую» анимацию, или что-то еще.


Редактировать: Конечно, если это возможно, я бынравится реализовывать игру таким образом, что даже представлению сущности не нужно знать тип состояния сущности.Если есть способ сделать это, то я бы использовал его.:) Я посмотрю в шаблон посетителя.

Ответы [ 9 ]

6 голосов
/ 22 июня 2011

Вы можете использовать dynamic_cast для этого:

if(DerivA * derivA = dynamic_cast<DerivA*>(obj)){
    // it is a DerivA
}
3 голосов
/ 22 июня 2011

Два способа:

Если ваши уроки полиморфны, dynamic_cast

или вы можете использовать typeid

Использование typeid

#include <typeinfo.h>


typeid(YourClass).name()

Использование dynamic_cast

DerivA& dynamic_cast<DerivA&> (object);
DerivA* dynamic_cast<DerivA*> (object);

должна быть хотя бы одна виртуальная функция в Базовом классе, чтобы заставить dynamic_cast работать, иначе вы получите ошибки компиляции.

Если вы попытаетесь привести к указателю на тип, который не является типом фактического объекта, результатом приведения будет NULL. Для аналогичной ситуации в случае ссылок приведёт исключение bad_cast.

1 голос
/ 22 июня 2011

Вопреки большинству предложений, я бы не использовал RTTI напрямую (typeinfo или dynamic_cast).Есть несколько вещей, которые вы можете сделать:

  1. добавить функцию, которая предоставляет информацию, необходимую для рисования
  2. использовать механизм двойной отправки

простейшее решение, вероятно, 1), просто добавьте виртуальный метод, который скажет вам, в каком состоянии находится объект, и используйте его, чтобы определить, как анимировать объект.Проблема этого подхода заключается в том, что он требует добавления методов в классы State для каждой из вещей, которые ему понадобятся: анимация, звук, расчеты движения ...

Использование формы двойной диспетчеризации, такой как посетительшаблон перемещает сложность из иерархии состояний в иерархию посетителей, которая должна содержать перегрузки для каждого отдельного состояния (на всех уровнях).Модель в приложении будет проще, но использование этой модели станет более громоздким.

1 голос
/ 22 июня 2011

Проблема, которую вы описали в последнем абзаце, может быть решена с помощью шаблон посетителя . Ты это пробовал? Он может решить проблему, даже не зная типа, на котором он работает.

1 голос
/ 22 июня 2011

Вы можете использовать dynamic_cast для определения типа объекта производного класса.Например, если вы выполните: DerivedA* p = dynamic_cast<Derived*>(pBase);, если условие p!=NULL удовлетворено, тогда это объект типа DerivedA.

1 голос
/ 22 июня 2011

Посмотрите на <typeinfo> часть стандартной библиотеки (например, см. Здесь .)

0 голосов
/ 22 июня 2011

Обычно лучшей альтернативой, чем попытка запроса типа объекта, было бы добавить виртуальную функцию в базовый класс:

class Base { public: virtual int Animation() const=0; };
class DerivA : public Base { public: int Animation() const { return 0; } };
class DerivB : public Base { public: int Animation() const { return 1; } };

И затем все разные анимации идентифицируются этим одним целым числом, возможно, имеющим немодифицируемый массив анимаций:

Animation anim1, anim2, anim3;
Animation *array[5] = { &anim1, &anim2, &anim3 };
void foo(Base *b) {
   int animnum = b->Animation();
   Animation *anim = array[animnum];
   ...
 }

Это как минимум один способ заставить его работать должным образом.

0 голосов
/ 22 июня 2011

Предполагая, что в ваших типах есть виртуальный метод, вы можете использовать идентификацию типа в реальном времени (RTTI) C ++ с такими вещами, как dynamic_cast и typeid

Однако, лучший дизайн может бытьреализовать виртуальные методы, чтобы полностью скрыть типы.Например:

class EntityState {
  virtual void Draw( Entity entity ) = 0;
  }

class DeadState : EntityState {
  virtual void Draw( Entity entity ) {
    //*** render the entity as dead
    }
  }

class AliveState : EntityState {
  virtual void Draw( Entity entity ) {
    //*** render the entity as alive!
    }
  }

class Entity {

  EntityState myEntityState;

  void Draw() {
    myEntityState.Draw( this );
    }
  }

Ваши сущности теперь могут быть нарисованы либо мертвыми, либо живыми без какого-либо кода оператора if-then-else или switch, который необходимо будет обновить, если вы вдруг захотите добавить новые состояния в вашу сущность.

0 голосов
/ 22 июня 2011

для наследования я бы посмотрел на static_cast и dynamic_cast. Вы можете использовать их, чтобы определить, унаследован ли объект от класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...