39

次のような、同じクラスのプライベート メンバーを持つべきクラスがあります。

class A {
    private:
        A member;
}

しかし、メンバーは不完全な型であることがわかります。なんで?ポインターを使用しても不完全な型はわかりませんが、ポインターは使用したくありません。どんな助けでも大歓迎です

4

8 に答える 8

44

メンバーを宣言する時点では、まだクラスを定義しているため、型は未定義のままです。AA

ただし、 を記述すると、コンパイラは がクラス名を表すA*ことを既に認識しているため、型「A へのポインター」が定義されます。そのため、定義している型へのポインターを埋め込むことができます。A

同じロジックが他のタイプにも適用されるため、単に次のように記述すると:

class Foo;

クラス Foo を宣言しますが、決して定義しません。あなたは書ける:

Foo* foo;

だがしかし:

Foo foo;

一方、Aコンパイラが再帰的な定義を許可した場合、型にどのようなメモリ構造を期待しますか?

ただし、同じ型の別のインスタンスを何らかの形で参照する型を持つことが論理的に有効な場合があります。人々は通常、そのためにポインターを使用します。または、スマートポインター ( などboost::shared_ptr) を使用して、手動で削除する必要がないようにします。

何かのようなもの:

class A
{
  private:
    boost::shared_ptr<A> member;
};
于 2011-06-14T20:41:23.847 に答える
28

これは、達成しようとしていることの実例です。

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

ハッピースタックオーバーフロー!

于 2011-06-14T21:14:00.973 に答える
5

A定義の最後まで「不完全」です (ただし、これにはメンバー関数の本体は含まれません)。

この理由の 1 つは、定義が終了するまで、 がどのくらい大きいかを知る方法がないためAです (これは、メンバーのサイズの合計と、その他のいくつかの要素に依存します)。あなたのコードはその良い例です: あなたの型Aは type のサイズによって定義されますA

明らかに、 type のオブジェクトには、同じ typeAのメンバー オブジェクトを含めることはできませんA

ポインターまたは参照を格納する必要があります。どちらかを保存したいのはおそらく疑わしいです。

于 2011-06-14T20:47:30.467 に答える
4

クラスが不完全である理由を理解する簡単な方法Aは、コンパイラの観点からクラスを調べてみることです。

とりわけ、コンパイラはAオブジェクトのサイズを計算できなければなりません。サイズを知ることは非常に基本的な要件であり、自動メモリでのスペースの割り当て、 operator の呼び出しnew、 の評価など、多​​くのコンテキストで現れsizeof(A)ます。ただし、のメンバーであるため、のサイズを計算するには、 のサイズをA知る必要があります。これにより、無限再帰が発生します。AaA

この問題に対処するコンパイラの方法は、Aその定義が完全にわかるまで不完全であると見なすことです。不完全なクラスへのポインターと参照を宣言することはできますが、値を宣言することはできません。

于 2016-08-31T14:00:12.623 に答える
2

A 内に A を含めることはできません。それが可能で、たとえば を宣言した場合は、無限A a;参照する必要があります。a.member.member.member...利用可能なRAMがそれほど多くありません。

于 2011-06-14T20:42:51.740 に答える
1

class Aのインスタンスに の別のインスタンスを含めるにはどうすればよいclass Aですか?

必要に応じて、A へのポインターを保持できます。

于 2011-06-14T20:44:05.667 に答える
1

このタイプのエラーは、まだ完全に定義されていないクラスを使用しようとすると発生します。

A* member代わりに使用してみてください。

于 2011-06-14T21:11:34.113 に答える
0

この問題は、コンパイラがコード内で A のオブジェクトに遭遇したときに発生します。コンパイラは手をこすり、A のオブジェクトの作成に着手します。そうしている間に、A が再び型 A のメンバーを持っていることがわかります。したがって、A のインスタンス化を完了するには、別の A をインスタンス化する必要があります。そうすることで、別の A などをインスタンス化する必要があります。境界のない再帰になってしまうことがわかります。したがって、これは許可されません。コンパイラは、クラスのオブジェクトのインスタンス化を開始する前に、すべてのメンバーのすべての型とメモリ要件を認識していることを確認します。

于 2015-02-10T10:28:17.687 に答える