我正在尝试构建一个包含三个文件的解决方案。使用main.cpp,它是四个文件。
Entity.h
#pragma once
#include "SystemBase.h"
namespace Engine {
class Entity {
public:
Entity() { }
void s(SystemBase* sb) { }
};
}
SubscribersList.h
#pragma once
#include "SystemBase.h"
#include "Entity.h"
namespace Engine {
class SubscribersList {
friend SystemBase;
public:
SubscribersList() { }
void f(Entity* e) { }
};
}
SystemBase.h
#pragma once
#include "SubscribersList.h"
#include "Entity.h"
namespace Engine {
class SystemBase {
public:
SystemBase() { }
void g(Entity* e) { }
private:
SubscribersList m;
};
}
不要专注于标题中的方法主体。这只是为了让事情变得简单。我发现了两种构建解决方案的方法。 1.在所有类名之前写下单词class。但是当我试图将实现与原型分开时,它会崩溃。 2.将所有代码写入一个文件。 我不会/不会在所有类名之前编写关键字class来构建解决方案,当然我不会/不会在一个文件中编写一个大项目。那我为什么不能建造呢?什么是魔术?!
答案 0 :(得分:0)
要理解循环头依赖的问题,我们首先需要理解类声明和定义之间的区别以及不完整类型的概念。
类型Type
的原型或前向声明写为:
class Type;
这样的前向声明允许您创建指针并引用该类型。
但是,在声明其完整类型之前,您无法实例化,取消引用指针或使用对Type
的引用。
Type
的声明可以写成:
class AnotherType;
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
现在我们可以创建声明实例,并且可以取消引用指向Type
的指针。
然而,在m_theOtherThing
取消引用或实例化之前AnotherType
必须完全声明。
class AnotherType {
Type m_aType;
}
应该这样做,这给了我们AnotherType
的完整声明和定义。
这允许继续编写Type::aMemberFunc
:
void Type::aMemberFunc() {
m_theOtherThing = new AnotherType();
}
如果不是按照这个顺序将此代码呈现给编译器,而是在前面提供Type
和AnotherType
的完整声明:
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
class AnotherType {
Type m_aType;
}
然后AnotherType *m_theOtherThing;
将无法编译,因为AnotherType
尚未在该点声明或转发。
切换顺序给出:
class AnotherType {
Type m_aType;
}
class Type {
public:
void aMemberFunc();
private:
AnotherType *m_theOtherThing;
};
现在Type m_aType;
将无法编译,因为Type
尚未声明。在这种情况下,前瞻性声明不会做。
使用#pragma once
而不是标题保护不会改变问题。 #pragma once
仅确保标题包含一次,否则它不会影响编译器处理代码的顺序。它肯定不允许编译器在到达它们时忽略未定义的类型。
对于这种类结构,编译器无法在不使用前向声明的情况下处理它。