这可能回答了很多次,但我似乎无法找到正确的帖子来讨论这个问题。
让我们假设我们有A,B和C类,它们是彼此的容器。这将需要他们必须包含彼此的头文件。但是当我在Visual Studio 2010中执行此操作时,我收到的错误是“包含太多文件:深度= 1024”。
在Java中,我可以拥有相互导入的类,但看起来使用C ++无法实现(为什么编译器不能真正处理它)。
无论如何,我该如何让它发挥作用?
答案 0 :(得分:3)
为避免循环引用,您可以将每个包含文件“包装”到预处理器#ifdef中。
档案A.h:
#ifndef SOMEREALLYUNIQUEIDFileAincluded
#define SOMEREALLYUNIQUEIDFileAincluded
#include "B.h"
class B;
/// Here you can use pointers to B
class A
{
// something about B*
};
#endif // SOMEREALLYUNIQUEIDFileAincluded
文件B.h:
#ifndef SOMEREALLYUNIQUEIDFileBincluded
#define SOMEREALLYUNIQUEIDFileBincluded
#include "A.h"
class A;
/// Here you can use pointer to A
class B
{
// something about A*
};
#endif // SOMEREALLYUNIQUEIDFileBincluded
#ifdef被称为“包含警卫”
对于现代编译器而不是编写“ifdefs”,您只能编写
#pragma once
在每个文件的开头。
编辑:
然后你使用C.cpp中的所有标题:
#include "A.h"
#include "B.h"
void test() {}
使用“gcc -c C.cpp”进行测试(仅限编译)。
EDIT2:
某种样本。具有可渲染对象的场景。
File Scene.h:
#ifndef SceneHIncluded
#define SceneHIncluded
class SceneObject;
class Scene {
public:
void Add(SceneObject* Obj);
void Render();
private:
std::vector<SceneObject*> Objects;
};
#endif // SceneHIncluded
File Scene.cpp:
#include "Scene.h"
#include "SceneObject.h"
void Scene::Add() { this->Objects.pusj_back(Obj); Obj->SceneRef = this; }
void Scene::Render() {
for(size_t j = 0 ; j < Objects.size() ; j++) { Objects[j]->Render(); }
}
文件SceneObject.h:
#ifndef SceneObjHIncluded
#define SceneObjHIncluded
class Scene;
class SceneObject {
public:
/// This is not the sample of "good" OOP, I do not suppose that
/// SceneObject needs this reference to the scene
Scene* SceneRef;
public:
// No implementation here
virtual void Render() = 0;
};
#endif // SceneObjHIncluded
SceneObject的实现可能是一些带变换的网格,即
class Mesh: public SceneObject {...}
在Mesh.h和Mesh.cpp文件中。
答案 1 :(得分:0)
通过尽可能在头文件中使用类和结构的前向声明,可以最好地避免循环引用。在非循环依赖中,使用前向声明还有一个额外的好处,即避免#include
其他文件,从而缩短编译时间。
在3个A,B和C类的例子中,A包含B,B包含C,C包含A;你可以做到以下几点:
<强> a.hpp:强>
#ifndef A_HPP
#define A_HPP
#include <memory>
#include <vector>
// Forward-declare B
struct B;
struct A
{
std::vector<std::shared_ptr<B>> bs;
};
#endif
<强> b.hpp:强>
#ifndef B_HPP
#define B_HPP
#include <memory>
#include <vector>
// Forward-declare C
struct C;
struct B
{
std::vector<std::shared_ptr<C>> cs;
};
#endif
<强> c.hpp:强>
#ifndef C_HPP
#define C_HPP
#include <memory>
#include <vector>
// Forward-declare A
struct A;
struct C
{
std::vector<std::shared_ptr<A>> as;
};
#endif
<强> main.cpp中:强>
#include "a.hpp"
#include "b.hpp"
#include "c.hpp"
int main()
{
std::shared_ptr<A> a(new A);
std::shared_ptr<B> b(new B);
std::shared_ptr<C> c(new C);
a->bs.push_back(b);
b->cs.push_back(c);
c->as.push_back(a);
}
用g ++编译的示例 - 4.7(这个概念同样适用于c ++ 98,你不能使用 shared_ptr<>
):
g++ -std=c++11 -pedantic main.cpp
在这种情况下,如果您需要使用其中一个依赖类的功能,并在相应的 .cpp 文件中使用该功能,则这一点非常重要。所以除了类本身的名称之外的任何东西。当 a.cpp #include
时,标题 a.hpp &amp; b.hpp , b.cpp #include
s b.hpp &amp; c.hpp 和 c.cpp #include
s c.hpp &amp; a.hpp 循环包含不会有问题,因为每个 .cpp 文件都被编译成自己的翻译单元,链接器将能够排序多个类定义没有问题,只要它们是相同的(它们将是相同的,因为它们来自相同的文件)。