1

クラス A と B があり、どちらもヘッダー ファイルにインクルード ガードがあります。1つは次のとおりです。

#ifndef A_H
#define A_H

#include "B.h"

class A
{
B b;
};

#endif

そしてもう1つは:

#ifndef B_H
#define B_H

#include "A.h"

class B
{
A a;
};

#endif

次に、次の main.cpp でテストします。

#include "A.h"

int main()
{
        A a;
}

コンパイルエラーは次のとおりです。

# make main
g++     main.cpp   -o main
B.h:8: error: ‘A’ does not name a type

ポインター/参照と前方宣言を使用する以外に、この状況に対する解決策はありますか?

4

4 に答える 4

4

いいえ、できません。そのうちの1つはポインタまたは参照である必要があります。AにBが含まれ、AにBが含まれている場合、再帰が無限になり、サイズが無限のオブジェクトを指定しようとしているためです。

于 2012-11-13T17:39:15.617 に答える
2

残念ながら、ポインタ/参照と前方宣言を使用する以外に選択肢はありません。

于 2012-11-13T17:38:19.267 に答える
1

それはできません。無限再帰が発生します(AにはBが含まれ、BにはAが含まれます)。さらに、クラス宣言の1つで他のクラスが不完全になるため、コンパイラはそれを許可しません。 。(完全には定義されていません)

それらの1つがポインタまたは参照である場合は、これを行うことができます。

于 2012-11-13T17:38:29.720 に答える
1

可能であれば、pImpl イディオムを使用することをお勧めします (実装へのポインター、その他の名前: 不透明ポインター、ハンドル本体イディオム、チェシャ猫 ... 詳細については、こちらを参照してください。)

基本的に、クラスのユーザーに通常表示される実装の詳細からクラス宣言を「解放」できます (privateアクセスを前提として、それらは使用できませんが)。

次のようにクラスを宣言するだけです。

#ifndef A_H
#define A_H

class A{
public:
     //declare public methods -> "interface"
private:
     struct Private;
     Private * mp_d;  //feel free to use smart pointer
};

#endif

前方宣言struct(または) はソース ファイルでclassのみ定義され、データ メンバーやクラス内部の関数などのすべての実装の詳細が含まれます。

#include "B.h"
struct A::Private {
      B a;
};


A::A() : mp_d( new Private()) {
} 

A::~A(){
    delete mp_d;   //not required if using smart pointer
}

注意:コンパイラによって生成されたコピー コンストラクターと代入演算子は、(予想どおり) 機能しなくなりました。それらを自分で実装するか、private(実装なしで) 宣言することによってコンパイラーがそれらを生成しないようにしてください。(これは基本的に C++03 スタイルです。C++11 では、コンパイラ生成を防ぐために宣言の後に追加するだけだと思います。)= delete

編集: pImpl の「長い」名前を追加

于 2012-11-13T17:56:00.137 に答える