3

这可能被回答了很多次,但我似乎找不到合适的帖子来讨论这个问题。

假设我们有类 A、B 和 C,它们是彼此的容器。这意味着他们必须包含彼此的头文件。但是当我在 Visual Studio 2010 中执行此操作时,我收到错误消息“包含文件过多:深度 = 1024”。

在 Java 中,我可以拥有相互导入的类,但 C++ 似乎无法做到这一点(为什么编译器不处理这个问题,真的)。

无论如何,我该如何让它工作?

4

2 回答 2

3

为了避免循环引用,您可以将每个包含文件“包装”到预处理器#ifdef 中。

档案啊:

#ifndef SOMEREALLYUNIQUEIDFileAincluded
#define SOMEREALLYUNIQUEIDFileAincluded

#include "B.h"

class B;

/// Here you can use pointers to B
class A
{
  // something about B*
};

#endif // SOMEREALLYUNIQUEIDFileAincluded

文件 B:

#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”(仅编译)对其进行测试。

编辑2:

某种样本。具有可渲染对象的场景。

文件场景.h:

#ifndef SceneHIncluded
#define SceneHIncluded

class SceneObject;

class Scene {
public:
   void Add(SceneObject* Obj);
   void Render();
private:
   std::vector<SceneObject*> Objects;
};

#endif // SceneHIncluded

文件场景.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 文件中。

于 2012-06-02T20:04:00.193 回答
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

主.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 s 标头a.hpp & b.hppb.cpp #include s b.hpp & c.hppc.cpp #include s c.hpp & a.hpp时,循环包含不会有问题,因为每个.cpp文件被编译到它自己的翻译单元中,并且链接器将能够毫无问题地整理出多个类定义,只要它们相同(它们将是相同的,因为它们来自相同的文件)。

于 2012-06-02T23:04:45.710 回答