13

次のコードは VC++6 でコンパイルされています。C2079: 'b' uses undefined class 'B'次のコードでコンパイル エラーが発生する理由がわかりません。

クラス B ソース

#include "B.h"

void B::SomeFunction()
{
}

クラス B ヘッダー

#include "A.h"

struct A;

class B
{
    public:
        A a;
        void SomeFunction();
};

構造体ヘッダー

#include "B.h"

class B;

struct A
{
    B b;
};

クラス B ヘッダーを次のように変更すると、エラーは発生しなくなります。しかし、ヘッダー宣言は先頭にありません!

奇妙なヘッダー宣言を持つクラス B ヘッダー

struct A;

class B
{
     public:
        A a;
        void SomeFunction();
};

#include "A.h"
4

6 に答える 6

20

クラスまたは構造体を定義するために、コンパイラはクラスの各メンバー変数の大きさを知る必要があります。前方宣言はこれを行いません。ポインターと(あまり頻繁ではありませんが)参照に使用されているのを見たことがあります。

それを超えて、あなたがここでやろうとしていることはできません。クラス A のオブジェクトを含む別のクラス B のオブジェクトをクラス A に含めることはできません。ただし、クラス Aのオブジェクトを含むクラス B へのポインタをクラス A に含めることはできます。

B.cpp

#include "B.h"

void B::SomeFunction()
{
}

Bh

#ifndef __B_h__  // idempotence - keep header from being included multiple times
#define __B_h__
#include "A.h"

class B
{
public:
    A a;
    void SomeFunction();
};

#endif // __B_h__

ああ

#ifndef __A_h__  // idempotence - keep header from being included multiple times
#define __A_h__
#include "B.h"

class B; // forward declaration

struct A
{
    B *b;  // use a pointer here, not an object
};

#endif // __A_h__

2点。まず、何らかの形式の冪等性を使用して、コンパイル単位ごとにヘッダーが複数回含まれないようにしてください。次に、C++ では、クラスと構造体の唯一の違いはデフォルトの可視性レベルであることを理解してください。クラスはデフォルトでプライベート可視性を使用し、構造体はデフォルトでパブリック可視性を使用します。次の定義は、C++ で機能的に同等です。

class MyClass
{
public: // classes use private visibility by default
    int i;
    MyClass() : i(13) { }
};

struct MyStruct
{
    int i;
    MyStruct() : i(13) { }
};
于 2009-12-11T02:40:04.497 に答える
4

次のような前方宣言

struct A;

また

class A;

A を不完全な型として導入すると、型の定義の最後に到達するまで不完全なままになります。不完全型でできることとできないことがあります。あなたはできる

  1. タイプ「A へのポインター」および「A への参照」の変数 (またはメンバー) を宣言します。
  2. 型 A の引数を取るか型 A を返す関数を宣言する

できません

  1. タイプ A の変数 (またはメンバー) を宣言する
  2. A へのポインターを逆参照するか、A への参照の任意のメンバーにアクセスします
  3. A のサブクラスを定義します。

コードで、不完全型の構造体メンバーを宣言しようとしています。それは違法です。ポインターと参照のみが許可されます。

于 2009-12-11T08:52:54.907 に答える
3
public:
    A a;

前方宣言のみで A のオブジェクトを作成しようとしています。現時点では (前方宣言のみの) コンパイラはオブジェクト A のサイズを決定できないため、A に必要なメモリを割り当てることができません。したがって、前方宣言のみでオブジェクトを作成することはできません。

代わりに次のように置き換えます。

A* a;

A のクラス定義のない A へのポインターまたは参照は正常に機能します。

于 2009-12-11T02:34:15.727 に答える
2

ここで 2 つの問題が飛び出します。

1: ;Struct Aの代わりに書いています。struct A小文字の「s」に注意してください。あなたのコンパイラは同等のものを考慮するかもしれませんが、それは標準の C++ ではないと思います。

Aと の間に循環参照を定義しましたB。各 A オブジェクトにはオブジェクトが含まれている必要がありBますが、各Bオブジェクトにはオブジェクトが含まれている必要がありAます。これは矛盾であり、思い通りにはいきません。この問題を解決する通常の C++ の方法は、A::bまたはB::a(または両方) のポインターまたは参照を使用することです。

于 2009-12-11T02:35:01.307 に答える
0

また、Bh から Ah を、Ah から Bh を含めます。少なくともプリプロセッサ マクロを使用する必要があります。

#ifndef __A_H__
#define __A_H__

// A.h contents

#endif

そのファイルが複数回含まれないようにします。

于 2009-12-11T02:46:23.860 に答える
0

A のインスタンスを作成すると、B のインスタンス (メンバー var) が作成され、A のインスタンス (メンバー var) が作成され、A のインスタンスを作成する B のインスタンスが作成されます。無限のメモリが必要なため、コンパイラはこれを許可しません。

これを解決するには、A または B のいずれかが他のクラスへの参照/ポインターを使用する必要があります。

于 2009-12-11T02:56:44.847 に答える