3

これはおそらく何トンも答えられますが、私はこの問題について話している正しい投稿を見つけることができないようです。

相互のコンテナであるクラスA、B、およびCがあると仮定します。これは、お互いのヘッダーファイルをインクルードする必要があることを意味します。しかし、Visual Studio 2010でこれを行うと、「インクルードファイルが多すぎます:depth=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

ファイルBh:

#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-cC.cpp」(コンパイルのみ)でテストします。

EDIT2:

ある種のサンプル。レンダリング可能なオブジェクトのあるシーン。

ファイルScene.h:

#ifndef SceneHIncluded
#define SceneHIncluded

class SceneObject;

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

#endif // SceneHIncluded

ファイル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ファイル内。

于 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

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

このような場合、依存クラスの1つからの機能を使用する必要がある場合は、対応する.cppファイルでその機能を使用することが重要です。つまり、クラス自体の名前以外のものです。a.cppがヘッダーa.hppb.hppb.cpp s b.hppc.hpp、およびc.cpp s c.hppa.hppの場合、循環インクルードに問題はありません。各.cpp#include #include #includeファイルは独自の変換ユニットにコンパイルされ、リンカは、それらが同一である限り(同じファイルからのものであるため)、問題なく複数のクラス定義を分類できます。

于 2012-06-02T23:04:45.710 に答える