我正在制作一个小游戏引擎,但是我被一些东西卡住了。说明:我有两个班,cEntity
和ObjectFactory
:
cEntity
构造器中添加新的cEnity
到ObjectFactory
,但面临与循环引用相关的错误:对于使用ObjectFactor::addEntity()
,我需要在cEntity
类中定义ObjectFactory.h
,但它创建了一个循环引用。
标题>
考虑到你对问题的描述,我认为你的代码可能存在潜在的架构问题。
你的ObjectFactory应该处理cEntities,这反过来应该不知道"上面的级别"。从你遇到的问题的描述来看,它暗示你不确定哪个类负责哪个工作。
你的cEntitys应该公开一个接口(即类中标记为"public"的所有东西),其他代码位与之交互。您的ObjectFactory(如果执行此工作,它的命名有点糟糕,但无论如何)应该依次使用该接口。开发者不应该关心谁在使用界面:他们有一项工作要做,他们就去做。ObjectFactory应该有一项工作需要它保存一个centity列表。当您在其他地方使用std::string时,您不会编辑它:为什么您的类有任何不同?
话虽这么说,解决循环依赖有两个部分(除了"首先不要创建具有循环依赖的代码"之外)——参见这个答案的第一部分。在我看来,这是避免这类问题的最好方法。
1)包括警卫。对每个头文件(.h)执行如下操作:
#ifndef CENTITY_H
#define CENTITY_H
class cEntity:public cEntityProperty
{
Vector2 position;
Vector2 scale;
public:
cEntity(void);
cEntity(const cEntity&);
~cEntity(void);
public:
void init();
void render();
void update();
void release();
};
#endif
- 第一次包含文件时,没有定义CENTITY_H。因此,
ifndef
宏为真,并移动到下一行(定义CENTITY_H),然后移动到标题的其余部分。 - 第二次(以及以后的所有时间),CENTITY_H被定义,因此
ifndef
宏直接跳到endif
,跳过您的标题。随后,头代码只会在编译后的程序中出现一次。如果您想了解更多细节,请尝试查看链接器进程。
2)类的前向声明。
如果ClassA需要一个ClassB类型的成员,而ClassB需要一个ClassA类型的成员,那么你就会遇到一个问题:两个类都不知道它需要分配多少内存,因为它依赖于包含它自己的另一个类。
解决方案是您有一个指向另一个类的指针。指针是编译器已知的固定大小,所以我们没有问题。但是,我们确实需要告诉编译器,如果它遇到一个我们之前还没有定义的符号(类名),不要太担心,所以我们在开始使用它之前只添加class Whatever;
。
在您的例子中,将cEntity实例更改为指针,并在开始时向前声明该类。您现在可以在cEntity中自由地使用ObjectFactory了。
#include "cEntity.h"
#include <vector>
class cEntity; // Compiler knows that we'll totally define this later, if we haven't already
class ObjectFactory
{
static std::vector<cEntity*> *entityList; // vector of pointers
static int i, j;
public:
static void addEntity(cEntity* entity) {
entityList->push_back(entity);
}
// Equally valid would be:
// static void addEntity(cEntity entity) {
// entityList->push_back(&entity);}
// (in both cases, you're pushing an address onto the vector.)
// Function arguments don't matter when the class is trying to work out how big it is in memory
private:
ObjectFactory(void);
~ObjectFactory(void);
};
std::vector<cEntity*> *ObjectFactory::entityList = new std::vector<cEntity*>();