私は同じクラスのプライベートメンバーを持つべきクラスを持っています:
class A {
private:
A member;
}
ただし、memberは不完全な型であることがわかります。どうして?ポインターを使用する場合、不完全な型を教えてくれませんが、ポインターを使用したくないです。どんな助けでも大歓迎です
メンバーを宣言するとき、あなたはまだ定義A
クラスなので、タイプA
は未定義のままです。
ただし、A*
、コンパイラはA
がクラス名を表していることをすでに知っているため、「Aへのポインタ」のタイプはdefinedです。そのため、定義している型へのポインタを埋め込むことができます。
同じロジックが他のタイプにも適用されるため、次のように記述した場合:
class Foo;
クラスFooを宣言しますが、定義することはありません。あなたは書ける:
Foo* foo;
だがしかし:
Foo foo;
一方、コンパイラが再帰的な定義を許可した場合、タイプA
にどのようなメモリ構造を期待しますか?
ただし、同じタイプの別のインスタンスを何らかの形で参照するタイプを持つことが論理的に有効な場合があります。人々は通常、それ以上のポインターを使用します:スマートポインター(boost::shared_ptr
)手動で削除する必要がないようにします。
何かのようなもの:
class A
{
private:
boost::shared_ptr<A> member;
};
これはあなたが達成しようとしていることの実例です:
class A {
public:
A() : a(new A()) {}
~A() { delete a; a = nullptr; }
private:
A* a;
};
A a;
ハッピースタックオーバーフロー!
A
は、その定義の終わりまで「不完全」です(ただし、これにはメンバー関数の本体は含まれません)。
この理由の1つは、定義が終了するまで、A
の大きさを知る方法がないことです(これは、メンバーのサイズの合計に加えて、他のいくつかのものに依存します)。あなたのコードはその良い例です。あなたのタイプA
はタイプA
のサイズによって定義されます。
明らかに、タイプA
のオブジェクトには、タイプA
のメンバーオブジェクトを含めることはできません。
ポインタまたは参照を保存する必要があります。どちらかを保存したいのではないかと思われます。
A内にAを含めることはできません。それを行うことができ、たとえば、A a;
、次を参照する必要がありますa.member.member.member...
無限に。それほど多くのRAMを利用できません。
class A
のインスタンスにclass A
の別のインスタンスを含めるにはどうすればよいですか?
必要に応じて、Aへのポインターを保持できます。
このタイプのエラーは、まだ完全に定義されていないクラスを使用しようとすると発生します。
代わりにA* member
を使用してみてください。
クラスA
が不完全である理由を理解する簡単な方法は、コンパイラーの観点から見てみることです。
とりわけ、コンパイラはA
オブジェクトのサイズを計算できなければなりません。サイズを知ることは、自動メモリ内のスペースの割り当て、演算子new
の呼び出し、sizeof(A)
の評価など、多くのコンテキストで現れる非常に基本的な要件です。ただし、A
のサイズを計算するには、A
がa
のメンバーであるため、A
のサイズを知る必要があります。これは無限再帰につながります。
この問題に対処するコンパイラの方法は、その定義が完全に知られるまでA
が不完全であると考えることです。不完全なクラスへのポインターと参照を宣言することはできますが、値を宣言することはできません。
この問題は、コンパイラがコード内のAのオブジェクトに遭遇したときに発生します。コンパイラーは手をこすり、Aのオブジェクトを作成します。その間、Aには再びタイプAのメンバーがあることがわかります。したがって、Aのインスタンス化を完了するには、別のAをインスタンス化し、そうすることで、別のAなどをインスタンス化する必要があります。無限に再帰することになります。したがって、これは許可されていません。コンパイラは、クラスのオブジェクトのインスタンス化を開始する前に、すべてのメンバーのすべての型とメモリ要件を確認します。