2017-06-28 3 views
3

C++クラスのフレンド関数、フレンドクラス、フレンドメンバー関数について学習しています。 は今、次のコードは、罰金コンパイル:C++フレンドクラスとフレンドメンバー関数

#include <iostream> 

class A 
{ 
public: 
    friend class B; 
    //friend void B::set(int i); 
    //friend int B::get(); 
    friend int function(A a); 
    A(int i); 
    void set(int i); 
    int get(); 
private: 
    int i; 
}; 

A::A(int i) : i(i) 
{ 
} 

void A::set(int i) 
{ 
    this->i = i; 
} 

int A::get() 
{ 
    return i; 
} 

class B 
{ 
public: 
    B(A a); 
    void set(int i); 
    int get(); 
private: 
    A a; 
}; 

B::B(A a) : a(a) 
{ 
} 

void B::set(int i) 
{ 
    a.i = i; 
} 

int B::get() 
{ 
    return a.i; 
} 

int function(A a); 

int main(int argc, char *argv[]) 
{ 
    A a(0); 
    std::cout << "in A i=" << a.get() << std::endl; 
    a.set(10); 
    std::cout << "in A i=" << a.get() << std::endl; 
    B b(a); 
    std::cout << "in B i=" << b.get() << std::endl; 
    b.set(21); 
    std::cout << "in B i=" << b.get() << std::endl; 
    std::cout << "function returns " << function(a) << std::endl; 
} 

int function(A a) 
{ 
    return a.i; 
} 

私は前方クラスB、または機能「機能」を宣言しなくてもクラスAに「機能」をクラスBに友情を付与すると機能するようにできています。今 、私はクラスBに2つのメンバ関数への友情を付与したい場合、私はクラスAを定義する前に、クラスBを定義しない場合、それは動作しません:

#include <iostream> 

class B; // doesn't work, incomplete type (complete type needed) 

class A 
{ 
public: 
    //friend class B; 
    friend void B::set(int i); 
    friend int B::get(); 
    friend int function(A a); 
    A(int i); 
    void set(int i); 
    int get(); 
private: 
    int i; 
}; 

A::A(int i) : i(i) 
{ 
} 

void A::set(int i) 
{ 
    this->i = i; 
} 

int A::get() 
{ 
    return i; 
} 

B::B(A a) : a(a) 
{ 
} 

void B::set(int i) 
{ 
    a.i = i; 
} 

int B::get() 
{ 
    return a.i; 
} 

int function(A a); 

int main(int argc, char *argv[]) 
{ 
    A a(0); 
    std::cout << "in A i=" << a.get() << std::endl; 
    a.set(10); 
    std::cout << "in A i=" << a.get() << std::endl; 
    B b(a); 
    std::cout << "in B i=" << b.get() << std::endl; 
    b.set(21); 
    std::cout << "in B i=" << b.get() << std::endl; 
    std::cout << "function returns " << function(a) << std::endl; 
} 

int function(A a) 
{ 
    return a.i; 
} 

が、私は、クラスBを定義することはできませんクラスAを定義する前に私は立ち往生しています。前方宣言(定義していない)はクラスBも動作しません。

だから私の質問は以下のとおりです。

1)私は友情宣言で関数やクラス全体を宣言転送する必要がありますが、私はそのクラスのメンバ関数を指定する必要がある場合、私はクラスを定義する必要がありますいけない理由? 私は、友情宣言は常識的な宣言ではないことを知っています(彼らは単にアクセス権を与え、何も宣言しません)。

2)私のコードをコンパイルするにはどうしたらいいですか?(AのメンバーオブジェクトをA *として宣言する以外に)

+1

実際、クラスAはパブリックインターフェイスを持っているため、クラスBのメンバー関数をフレンド関数として宣言する必要はありません。 –

+0

@ VladfromMoscowそれは確かに人為的な例です。私はちょうどそれがうまくいかないと私はそれを回避することができます理解したい。 – Luca

+0

"クラスAを定義する前にクラスBを定義できません"なぜですか? –

答えて

1

友人のクラスとその使い方の例を示します。これは取られたcplusplus.comあなたの例が本当に友情の適切な使用をC++で説明していないため、私がこれを投稿している理由です。どのように/なぜあなたが友情を使用すべきかについて、これがいくつかの光を放つことを願っています。それはあなたの前方宣言問題を解決することにつながります。この例では

// friend class 
#include <iostream> 
using namespace std; 

class Square; 

class Rectangle { 
    int width, height; 
    public: 
    int area() 
     {return (width * height);} 
    void convert (Square a); 
}; 

class Square { 
    friend class Rectangle; 
    private: 
    int side; 
    public: 
    Square (int a) : side(a) {} 
}; 

void Rectangle::convert (Square a) { 
    width = a.side; 
    height = a.side; 
} 

int main() { 
    Rectangle rect; 
    Square sqr (4); 
    rect.convert(sqr); 
    cout << rect.area(); 
    return 0; 
} 

は、クラスの長方形が 長方形のメンバ関数は、プライベートと保護されたメンバー広場の にアクセスすることを可能にするクラス・スクエアの友人です。より具体的には、Rectangleは、メンバー変数 Square :: sideにアクセスします。これは、四角形の辺を表します。

この例では新しいことがあります: プログラムの冒頭には、Square Squareという空の宣言があります。 RectangleクラスはSquareを使用し( メンバー変換ではパラメータとして)、SquareはRectangleを使用して(友達として宣言しているため)、 が必要です。

この例では、 長方形はSquareの友人クラスとみなされていますが、Squareは ではなくRectangleの友人とみなされています。したがって、 Rectangleのメンバー関数はSquareの保護されたメンバーとプライベートメンバーにアクセスできますが、他の方法では ではありません。もちろん、スクエアは、必要に応じて、このようなアクセスを許可するRectangleの友人 と宣言することもできます。

友人関係のもう1つの特性は、推移的でないということです。 友だちの友人は、明示的に が指定されていない限り、友人とはみなされません。

0

class Bをの友人にしてください。これに悪影響はありません。

あなたは絶対に積極的に、よりきめの細かい制御を行使したい場合は、(骨を裸ストリッピングあなたの例を使用して)このようなプロキシクラスでそれを行うことができます。

class Proxy; 

class A 
{ 
public: 
    friend class Proxy; 
    A(int i); 
private: 
    int i; 
}; 

class B 
{ 
public: 
    B(A a); 
    void set(int i); 
    int get(); 
private: 
    A a; 
}; 

class Proxy 
{ 
    friend void B::set(int); 
    friend int B::get(); 
    static int& get_i(A& a) { return a.i; } 
    static const int& get_i(const A& a) { return a.i; } 
}; 

あなたは今Proxy::get_i(a)を代わりに使用することができますa.iB::setB::get(唯一)です。

+0

この場合、私はプロキシクラスの前方宣言も必要ありません – Luca