次のような、同じクラスのプライベート メンバーを持つべきクラスがあります。
class A {
private:
A member;
}
しかし、メンバーは不完全な型であることがわかります。なんで?ポインターを使用しても不完全な型はわかりませんが、ポインターは使用したくありません。どんな助けでも大歓迎です
次のような、同じクラスのプライベート メンバーを持つべきクラスがあります。
class A {
private:
A member;
}
しかし、メンバーは不完全な型であることがわかります。なんで?ポインターを使用しても不完全な型はわかりませんが、ポインターは使用したくありません。どんな助けでも大歓迎です
メンバーを宣言する時点では、まだクラスを定義しているため、型は未定義のままです。A
A
ただし、 を記述すると、コンパイラは がクラス名を表すA*
ことを既に認識しているため、型「A へのポインター」が定義されます。そのため、定義している型へのポインターを埋め込むことができます。A
同じロジックが他のタイプにも適用されるため、単に次のように記述すると:
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
は type のサイズによって定義されますA
。
明らかに、 type のオブジェクトには、同じ typeA
のメンバー オブジェクトを含めることはできませんA
。
ポインターまたは参照を格納する必要があります。どちらかを保存したいのはおそらく疑わしいです。
クラスが不完全である理由を理解する簡単な方法A
は、コンパイラの観点からクラスを調べてみることです。
とりわけ、コンパイラはA
オブジェクトのサイズを計算できなければなりません。サイズを知ることは非常に基本的な要件であり、自動メモリでのスペースの割り当て、 operator の呼び出しnew
、 の評価など、多くのコンテキストで現れsizeof(A)
ます。ただし、のメンバーであるため、のサイズを計算するには、 のサイズをA
知る必要があります。これにより、無限再帰が発生します。A
a
A
この問題に対処するコンパイラの方法は、A
その定義が完全にわかるまで不完全であると見なすことです。不完全なクラスへのポインターと参照を宣言することはできますが、値を宣言することはできません。
A 内に A を含めることはできません。それが可能で、たとえば を宣言した場合は、無限A a;
参照する必要があります。a.member.member.member...
利用可能なRAMがそれほど多くありません。
class A
のインスタンスに の別のインスタンスを含めるにはどうすればよいclass A
ですか?
必要に応じて、A へのポインターを保持できます。
このタイプのエラーは、まだ完全に定義されていないクラスを使用しようとすると発生します。
A* member
代わりに使用してみてください。
この問題は、コンパイラがコード内で A のオブジェクトに遭遇したときに発生します。コンパイラは手をこすり、A のオブジェクトの作成に着手します。そうしている間に、A が再び型 A のメンバーを持っていることがわかります。したがって、A のインスタンス化を完了するには、別の A をインスタンス化する必要があります。そうすることで、別の A などをインスタンス化する必要があります。境界のない再帰になってしまうことがわかります。したがって、これは許可されません。コンパイラは、クラスのオブジェクトのインスタンス化を開始する前に、すべてのメンバーのすべての型とメモリ要件を認識していることを確認します。