C ++:用索引数组替换Long Switch()语句?

时间:2011-02-23 11:13:55

标签: c++ arrays

要动态创建游戏对象,我会使用 ObjectTypeID ,这是 unsigned int ,并让它在很长的时间内进行比较 switch()声明。如果找到适当的swith case,我创建对象并存储它。因为我已经拥有90个游戏对象,所以Switch()已经很长,并且会增长到大约300个对象。

为了避免超长的switch()语句,并提高速度,完美的候选者将利用索引数组来存储所有对象类型(ObjectTypeID从0向上增加)。 有没有办法,如何在数组中存储对象类型?

我想使用这样的东西:

  • aObjectTypesArray [ObjectTypeID] * pNewDynamicObject = new aObjectTypesArray [ObjectTypeID];

请问如何在我的情况下如何利用动态数组索引,以及如何避免超长的switch()语句?您的建议可能与我的想法不同,关键是使用数组索引并删除long switch()语句。

3 个答案:

答案 0 :(得分:8)

在c ++中,类不是第一类对象,因此您无法直接执行所需的操作。但是,如果游戏对象继承自公共基类,则只需使用工厂。

class GameObject {
};

class GameObjectFactory {
public:
  virtual GameObject * create() = 0;
};

class SomeGameObject : public GameObject {
};

class SomeGameObjectFactory : public GameObjectFactory {
  virtual GameObject * create() { return new SomeGameObject; }
};

然后将工厂实例存储在数组中。

答案 1 :(得分:2)

创建工厂的一种更简单的方法是使用模板创建工厂方法,然后使用函数指针或boost::functionstd::function存储它(如果它们可用)。

例如,给定对象:

#include <iostream>

struct GameObject {
    virtual ~GameObject() {}
    virtual void foo() const = 0;
};

struct ExampleObject : GameObject {
    void foo() const { std::cout << "ExampleObject::foo\n"; }
};

我们可以使用模板来定义通用对象工厂:

template <typename Object>
GameObject* object_factory() const
{
    return new Object();
};

定义一个向量来存储工厂方法的函数指针:

#include <vector>

typedef GameObject*(*factory_ptr)();
std::vector<factory_ptr> factories;

然后使用类似的东西向工厂添加一个对象:

int example_object_id = factories.size();
factories.push_back(&object_factory<ExampleObject>);

然后用以下方法创建对象:

GameObject* obj = factories[example_object_id]();

这是一个完整的例子:

#include <iostream>
#include <vector>

template <typename BaseObject>
class game_object_factory
{
    template <typename Object>
    static BaseObject* create_object()
    {
         return new Object();
    };

    typedef BaseObject*(*factory)();
    std::vector<factory> factories;

public:
    template <typename Object>
    int register_type()
    {
        int index = factories.size();
        factories.push_back(&create_object<Object>);
        return index;
    }

    BaseObject* create(int id) const {
        return factories[id]();
    }
};

struct GameObject {
    virtual ~GameObject() {}
    virtual void foo() const = 0;
};

struct Example1 : GameObject {
    void foo() const { std::cout << "Example1::foo\n"; }
};

struct Example2 : GameObject {
    void foo() const { std::cout << "Example2::foo\n"; }
};

int main() {
    game_object_factory<GameObject> factory;

    int obj1_id = factory.register_type<Example1>();
    int obj2_id = factory.register_type<Example2>();

    // Should use a smart pointer here to simplify memory management.
    GameObject* obj = factory.create(obj2_id);
    obj->foo();
    delete obj;
}

答案 2 :(得分:1)

我认为Erik给出了一个很好的答案,即使用Factory设计模式并使用Factory实例填充数组。

我唯一需要注意的是,使用ID作为数组索引会产生一些维护开销 - 您需要确保ID和数组内容匹配。当你有10个ID时很容易,当你有300个时就不那么简单了,当代码被维护了几个月或几年时,肯定不那么简单。

如果你能够在性能上受到影响(我很欣赏这可能是一个主要考虑因素)那么最好使用某种类型的地图(我将实现选择留给你!),其中数组的每个条目都包含一个ID 其对应的工厂实例。这样,您可以逻辑地对对象进行分组,而不必以数字​​方式对它们进行排序,并且对象ID不需要是连续的。但无论哪种方式,工厂都是一个很好的方式。