Определение типа объекта в иерархии - PullRequest
1 голос
/ 07 февраля 2012

У меня есть иерархия игровых объектов:

class GameObject {
public:
    virtual void update(float dt) = 0;
    virtual void draw() = 0;
};
class Building : public GameObject {}
class Sawmill : public Building {}
class Human : public GameObject {}

и так далее. Все объекты управляются игрой (которая не является подклассом GameObject :). Игра сохраняет все объекты в std :: vector и успешно вызывает виртуальные методы, такие как update и draw, и это все хорошо. Но иногда мне нужно определить, с каким типом GameObject я имею дело. Для этого случая мы придумали решение: GameObject имеет перечисление типов GameObject, и каждый подкласс GameObject возвращает свое собственное значение из этого перечисления.

class GameObject {
public:
    enum GOType
    {
        GOGameObject,
        GOBuilding,
        GOSawmill,
        GOHuman,
        ...
    }
    static GOType Type() { return GOGameObject; }
    virtual GOType getType() const { return GameObject::Type(); }
};

class Building : public GameObject {
public:
    static GOType Type() { return GOBuilding; }
    virtual GOType getType() const { return Building::Type(); }
};

Итак, у каждого подкласса GameObject есть своя собственная версия метода «static GOType Type ()», которая возвращает значение из enum GOType. И он перегружен виртуальным методом «GOType getType () const», который просто вызывает собственный метод класса Type (). В любом месте игры я могу проверить, является ли объект, на который у меня есть указатель, например, зданием:

if (obj && obj->getType() == Building::Type()) {
    // then do stuff
}

Чтобы прояснить ситуацию - это решение отлично работает и зарекомендовало себя как расширяемое и очень эффективное (первое решение, которое мы придумали, это возвращение строк в getType () и сравнение их; это было очень медленно).

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

Итак, мой вопрос: есть ли другое решение проблемы, столь же эффективное, как это, но без необходимости расширения GOType в GameObject?

Ответы [ 4 ]

2 голосов
/ 07 февраля 2012

Вместо огромной цепочки унаследованных классов, почему бы вам не создать шаблон для ваших draw и update функций, чтобы вы могли передать любой T, и он будет делать все, что вам нужно. Если вам нужно различное поведение для конкретного T, вы можете специализироваться.

Просто предложение.

1 голос
/ 07 февраля 2012

Вы можете использовать dynamic_cast.

if ( dynamic_cast<Building*>(obj) ) 
{
    // then do stuff
}

Нет необходимости в методе enum или getType().

0 голосов
/ 07 февраля 2012

Использовать dynamic_cast: http://msdn.microsoft.com/en-us/library/cby9kycs%28v=VS.80%29.aspx

Некоторые примеры вы найдете в ссылке.

0 голосов
/ 07 февраля 2012

У меня ощущение, что вы должны знать, что они печатают во время выполнения, тогда, возможно, есть проблема с дизайном. Если вы вызываете «Делать вещи» на объектах, то использование виртуальных функций и полиморфизм означают, что вам не нужно знать, что это за объект.

Но это говорит о том, что если у вас включен RTTI, то это, по-видимому, способ определить, какие типы объектов находятся во время выполнения, без необходимости добавлять их тип в базовый класс.

typeid может использоваться для определения типа во время выполнения.

...