4

クラス A とクラス B を作成しました。タイプ B のベクトルを A に設定し、タイプ A のベクトルを B に設定しようとしています。

クラス A ヘッダー:

#ifndef A_H_
#define A_H_

#include "B.h"
#include <vector>
using namespace std;
class A {

public:
    vector<B> bvector; // here is the error
    A();
};

#endif /* A_H_ */

クラス B ヘッダー:

#ifndef B_H_
#define B_H_
#include "A.h"
#include <vector>

using namespace std;

class B {
vector<A> aVector; //Here is the error

public:
    B();
};

#endif /* B_H_ */

しかし、次のエラーが発生します。

"..\src/Bh:16:8: エラー: 'A' はこのスコープで宣言されていません

..\src/Bh:16:9: エラー: テンプレート引数 1 が無効です

..\src/Bh:16:9: エラー: テンプレート引数 2 が無効です"

B の悪い行を削除すると、どちらが反転しA.hますか。何が間違っていますか?

4

3 に答える 3

2

クラスAとクラスBを作成し、タイプBのベクトルをAに設定し、タイプAのベクトルをBに設定しようとしています

クラス間に循環依存関係を作成しています。これは一般的に悪いことであり、特に C++ ではそうです。

コンパイラは、A をコンパイルするために、B の定義 (#include "Bh") を知る必要があります。残念ながら、B ヘッダーには A クラスへの参照が含まれています (これが循環参照です)。A ヘッダーは現在の TU に既に含まれているため、コンパイラはこの状況を処理できません (インクルード ガードを参照)。

循環参照を持つことは設計が悪いことの兆候であることが多いという事実にもかかわらず、最終的には前方宣言を使用して問題を克服できます。たとえば、次のように B を変更できます。

#ifndef B_H_
#define B_H_

#include <vector>

using namespace std;
class A; //forward declaration of class A
class B {
vector<A*> aVector; //note that you must only use pointer to A now 

public:
    B();
};

#endif /* B_H_ */

前方宣言を使用すると、基本的に、型 A が別の場所で定義されることをコンパイラに伝えます。コンパイラはこの事実に頼ることができますが、A については何も知りません (特に、A とそのメソッドのサイズを無視します)。したがって、B 内で A を前方宣言した場合、A クラスへのポインターのみを使用でき (ポインターは常に同じサイズです)、B 内から A クラスのメソッドを呼び出すことはできません。

于 2012-11-04T22:24:14.780 に答える
1

ここでのコツは、2 つのクラスのうちの 1 つを前方宣言する必要があるということです。残念ながら、前方宣言では、ヘッダーで完全な型を使用することはできません。型へのポインターのみを使用できます。したがって、この場合でもそれは機能しません。

この問題を回避するには、 PIMPL イディオム (Pointer to IMPLementation) (google that) を使用できます。

PIMPL イディオムでは、基本的に 3 番目のタイプを作成する必要があります。次に、タイプ B は、タイプ A のベクターを含む実装クラスへのポインターを保持します。B に保持されるはずだったベクターのすべての操作は、実際に A のベクターを保持する新しい実装クラスに転送されます。

例えば:

//Forward declare impl class.
class BImpl;

class B {
    private:
        BImpl* impl;

    public:
        void PrintVector() { impl->PrintVector(); }
};

class A {
    private:
        std::vector<B> vec;

    public:
        void PrintVector() { /* Do printing */ }
};

class BImpl {
    private:
        std::vector<A> vec;

    public:
        void PrintVector() { /* Do Printing */ }
};

これらのクラスのコンストラクターまたは人口メソッドは含めていませんが、一般的なアイデアを得る必要があります:)

于 2012-11-04T22:20:59.363 に答える
0

循環依存関係があります。

A.hが含まれB.hていますA.hが、A_H_ガードは既に定義されているため、 の内容A.hはスキップされ、 の内容は処理B.hAれます。A.h#define#includeA.h

于 2012-11-04T22:22:56.577 に答える