20

C ++入門書によると、著者は、クラス全体ではなく、別のクラスのフレンドとしてクラスメンバー関数を指定できると述べています(634ページ)。

次に、このコードをテストしました。

class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};

全体ではなく、のfB()友達になりたかっただけです。しかし、上記のコードはエラーを生成しました:。(私はVisual C ++ 2005を使用しています)class Aclass B'B' : is not a class or namespace name

4

7 に答える 7

22

Aの前にBの定義を入れてみてください。

class A; // forward declaration of A needed by B

class B
{
public:
    // if these require full definition of A, then put body in implementation file
    void fB(A& a); // Note: no body, unlike original.
    void fB2(A& a); // no body.
};

class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};

Aの完全な定義が必要ですB。ただし、Bについて知るA必要がありますが、完全な定義は必要ないため、の前方宣言が必要ですA

于 2012-05-11T06:24:02.073 に答える
6

コンパイラがコードのコンパイルを開始し(通常は上から)、次の行が発生した場合:

friend void B::fB(A& a);
  1. この時点で、コンパイラはBの型情報を認識していないため、エラーがスローされます('B':はクラス名または名前空間名ではありません)。

  2. クラスBの前方宣言により、コンパイラーは、すべてのメンバーによる実際の宣言よりも前に、Bのタイプがクラスであることを認識します。

  3. クラスBの前方宣言の後、以下のコードを実行します。

///////////////

class B;
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){};
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};

それでもエラー!!!

前方宣言は、プログラマーがまだ完全な定義を与えていない識別子の宣言にすぎないためです。したがって、コンパイラはクラスAの前にBの完全な定義を必要とします。

注:クラスAの定義はBのタイプとBの定義(つまりB :: fB)に依存するため、前方宣言だけでは解決できません。クラスBの完全な定義はクラスAの前に定義する必要があります。

4このコードを実行します

////////

class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){}
};

それでもエラー!!!

クラスBのメンバー関数fBおよびfB2はタイプAの引数を持っていますが、コンパイラーはAのタイプ情報を認識しないため、クラスAの前方宣言により、コンパイラーにAのタイプ情報を通知できます。注:クラスBの定義はにのみ依存します。 AのメンバーではなくAのタイプであるため、Aの前方宣言はステップ4を解決します。

  1. 最終コード

////////////////////////

class A;  // forward declaration of A needed by B
class B
{
public:
    void fB(A& a);
};

class A
{
    int i;
public:
    friend void fA(A& a);    //specifying function fA as a friend of A, fA is not member function of A
    friend void B::fB(A& a); //specifying B class member function fB as a friend of A
};

// fA is Friend function of A
void fA(A& a)
{
    a.i  = 11; // accessing and modifying Class A private member i
    cout<<a.i<<endl;
}

// B::fB should be defined after class A definition only because this member function can access Class A members
void B::fB(A& a)
{
    a.i  = 22; // accessing and modifying Class A private member i in Class B member function fB
    cout<<a.i<<endl;
}

int main()
{
    A a;
    fA(a);    // calling friend function of class A

    B b;
    b.fB(a);  // calling B class member function fB, B:fB is friend of class A

    return 0;
}

6演習:

// Cyclic dependency 
#include<iostream>
using namespace std;

class A;

class B
{
public:
    void fB(A& a);
    friend void A::fA(B& b); //specifying class A's member function fA as a friend of B
};

class A
{
    int i;
public:
    void fA(B& b);  
    friend void B::fB(A& a); //specifying class B's member function fB as a friend of A
};

int main()
{
    return 0;
}
于 2015-03-19T05:07:35.677 に答える
3

これが機能するためには、の定義の前にの完全な定義をB知る必要がありますA

したがって、完全な型は必要ないためA、前方宣言し、定義を切り替えます。B

class A;
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
于 2012-05-11T06:23:14.073 に答える
2

コンパイラがコードの読み取りを開始し(通常は上から)、次の行が検出された場合:

friend void B::fB(A& a);

そうすると、コンパイラはこれが何を意味するのか理解できませんB::。コードの後半でこのクラスを定義したが、コンパイラーはそれを認識していません。したがって、定義がコードの後半にある場合は、通常、class()の前方宣言を行うことをお勧めclass Name;します。

于 2015-02-24T18:45:59.107 に答える
0

最初にクラスAを前方宣言して、クラスBの定義に表示されるようにします。次に、クラスBのフレンド関数を含むクラスAを定義します。

于 2014-11-26T12:38:57.997 に答える
0

まず、特定のクラス名を使用する前に、まずそれを宣言する必要があります。したがって、クラスBが最初に宣言される前に、クラスAでクラスBを使用しているため、クラスBの前方宣言が必要になります。

次に、両方のクラスを定義した後、関数(両方のクラスの変数を使用しています。ここではフレンド関数)を定義する必要があります。そうしないと、エラーが発生する可能性があります。

例えば

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}

クラスの前方宣言があったとしても、put_bataが定義される前にrollとidにアクセスしようとするとエラーが表示されますが、以下に示すコードは問題なく機能します。

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}


int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}
于 2014-12-20T13:38:06.883 に答える
0

@juanchopanza @ipkiss Aがまだ定義されていないため、fB(A&a)内のAのデータメンバーにアクセスできないという問題について。別のファイルで定義して含める代わりに、クラスAの定義の後に関数fB(A&a)を定義するだけで、fB(A&a)がAのデータメンバーを表示できるようになります。

于 2014-12-23T12:25:38.240 に答える