限制包括在C ++中

时间:2012-03-08 23:06:09

标签: c++ inheritance include

我在新手C ++项目中遇到包含重载的各种问题,但我不确定如何避免它。

如何避免必须包含数十个类的问题,例如在地图加载方案中:

这是一个简单的示例Map类,它将从文件中加载游戏地图:

// CMap.h
#ifndef _CMAP_H_
#define _CMAP_H_
class CMap {
    public:
        CMap();
        void OnLoad();
};
#endif

// CMap.cpp
#include "CMap.h"
CMap::CMap() {
}

void CMap::OnLoad() {
    // read a big file with all the map definitions in it here
}

现在让我说我有很多怪物加载到我的地图中,所以我可能有一个列表或其他结构来保存我在地图中的所有怪物定义

std::list<CMonster*> MonsterList;

然后我可以在我的CMap.h中简单地向前声明“CMonster”,并在该列表中添加尽可能多的怪物

// CMap.h
class CMonster;

// CMap.cpp
void CMap::OnLoad() {
    // read a big file with all the map definitions in it here
    // ...
    // read in a bunch of mobs
    CMonster* monster;
    MonsterList.push_back(monster);
}

但是如果我有很多不同类型的怪物呢?如何在不包含每个CMonster_XXX.h的情况下创建许多不同类型的怪物?并且还使用那些方法?

// CMap.cpp
void CMap::OnLoad() {
    // read a big file with all the map definitions in it here
    // ...
    // read in a bunch of mobs
    CMonster_Kitten* kitty;
    kitty->OnLoad();
    MonsterList.push_back(kitty);

    CMonster_Puppy *puppy;
    puppy->OnLoad();
    puppy->SetPrey(kitty);
    MonsterList.push_back(puppy);

    CMonster_TRex *awesome;
    awesome->OnLoad();
    awesome->SetPrey(puppy);
    MonsterList.push_back(awesome);
}

5 个答案:

答案 0 :(得分:3)

这是我用来包含事物的规则。

  • 在头文件中尽可能多地向前声明。
  • 在.cpp
  • 中包含您需要的任何.h
  • 除非必须,否则不要在其他.h中包含.h。
  • 如果您的项目构建而不需要包含.h,那么您没问题。 (主要是,只要您的编译器足够合规)

编辑:此外,您可能需要阅读Large-Scale C++ Software Design。它讨论了管理物理文件依赖性。

答案 1 :(得分:2)

您可以创建一个文件myMonstersInclude.h,如

#include "myMonster1.h"
#include "myMonster2.h"
....

你的主要代码只需要`#include“myMonstersInclude.h”。

您甚至可以使用构建工具生成它,大多数允许您在每个步骤之前和之后运行自己的脚本。

答案 2 :(得分:0)

简短的回答是:你不能。

稍长的是:您可以创建一个只包含其他文件的头文件,并在.cpp文件中包含新的头文件。这仍然有效地包括了所有的标题,你只是没有包含重复的列表,这就是为什么我说短裤的答案是你不能。

新标题类似于:

#include CMonster_cat
#include CMonster_puppy
...

答案 3 :(得分:0)

问题是,你的地图真的是否需要了解怪物的所有类型?可能不是 - 只要知道他们派生自CMonster 就地图而言应该足够了。地图类使用的所有方法都应该能够通过怪物上的虚函数进行操作,因此每个怪物类型都定义了它的专用行为,而不是地图。

我怀疑通过在这里正确使用继承来大大减少你的“包含问题”。

答案 4 :(得分:0)

您可以使用工厂功能。结合全局静态对象来注册类型。像这样:

// in some main file...
typedef CMonster*(*create_ptr)();

std::map<std::string, create_ptr> &get_map() {
    // so we can make sure this exists...
    // NOTE: we return a reference to this static object
    static std::map<std::string, create_ptr> map;
    return map;
}

我们添加了一些胶水代码来注册创建函数......

// in each type of monster class (ex: CMonsterA)
CMonster *create_monster_a() {
    return new CMonsterA;
}

static struct monsterA_Registrar {
    monsterA_Registrar() {
        get_map().insert(std::make_pair("MonsterA", create_monster_a));
    }
} register_monsterA;

最后,回到主文件中,你可以通过它的类型名称创建一个怪物对象......

std::map<std::string, create_ptr>::iterator it = get_map().find("MonsterA");
if(it != get_map().end()) {
    return (it->second)();
}

throw "invalid monster type requested";

以下是发生的事情:

当程序启动时,在main之前,它将运行全局对象的所有构造函数,在这种情况下register_monsterA就是其中之一。

这个对象的构造函数将获得get_map()(它不能只是一个全局static,因为如果我们这样做,我们无法知道什么顺序被初始化,所以它是一个函数)。

然后它会向它添加一个项目,它是一个“创建函数”,基本上是一个能够创建新CMonster的函数。

最后,为了制作怪物,我们只需查看相同的地图,然后获取创建功能并运行它(如果存在的话)。


编辑:这是一个完整的工作示例...(有一些宏观魔法使其更清洁)

CMonster.h

class CMonster {
public:
    virtual ~CMonster() {
    }

    virtual void roar() = 0;
};

typedef CMonster*(*create_ptr)();

std::map<std::string, create_ptr> &get_map();

#define MONSTER_REGISTRAR(name) \
CMonster *create_monster_##name() { \
    return new C##name; \
}\
 \
static struct monster##name##_Registrar {\
    monster##name##_Registrar() { \
        get_map().insert(std::make_pair(#name, create_monster_##name));\
    } \
} register_monster##name;

CMonster.cc

std::map<std::string, create_ptr> &get_map() {
    // so we can make sure this exists...
    // NOTE: we return a reference to this static object
    static std::map<std::string, create_ptr> map;
    return map;
}

CMonsterA.cc

#include "CMonster.h"
class CMonsterA : public CMonster {
public:
    CMonsterA() {
        std::cout << "HERE - A" << std::endl;
    }
    virtual void roar() {
        std::cout << "A" << std::endl;
    }
};

MONSTER_REGISTRAR(MonsterA)

CMonsterB.cc

#include "CMonster.h"
class CMonsterB : public CMonster {
public:

    CMonsterB() {
        std::cout << "HERE - B" << std::endl;
    }
    virtual void roar() {
        std::cout << "B" << std::endl;
    }
};

MONSTER_REGISTRAR(MonsterB)

main.cc

#include "CMonster.h"

CMonster *get_monster(const std::string &name) {
    std::map<std::string, create_ptr>::iterator it = get_map().find(name);
    if(it != get_map().end()) {
        return (it->second)();
    }

    throw "invalid monster type requested";
}

int main() {

    CMonster *monster = get_monster("MonsterB");
    monster->roar();
    delete monster;
}