friend
(C++)
状況によっては、クラスが、クラスのメンバーではない関数または別のクラス内のすべてのメンバーに対してメンバー レベルのアクセス権を付与すると便利です。 これらの無料の関数とクラスは、キーワード (keyword)によってマークされたfriend
フレンドと呼ばれます。 クラスの実装側が自分のフレンドを宣言することだけが可能です。 関数またはクラスは、クラスのフレンドとして自分自身を宣言することはできません。 クラス定義では、キーワード (keyword)と非メンバー関数またはその他のクラスの名前を使用friend
して、クラスのプライベートメンバーと保護されたメンバーへのアクセスを許可します。 テンプレート定義では、型パラメーター friend
を .
構文
friend-declaration
:
friend
function-declaration
friend
function-definition
friend
elaborated-type-specifier
;
;
friend
simple-type-specifier
;
friend
typename-specifier
;
friend
宣言
以前に宣言されていない関数を friend
宣言すると、その関数は外側の非クラス スコープにエクスポートされます。
宣言でfriend
宣言された関数は、キーワード (keyword)を使用してextern
宣言されたかのように扱われます。 詳細については、extern
を参照してください。
グローバル スコープを持つ関数はプロトタイプの前に関数として friend
宣言できますが、メンバー関数は、完全なクラス宣言の外観の前に関数として friend
宣言することはできません。 次のコードは、このような宣言が失敗する方法を示しています。
class ForwardDeclared; // Class name is known.
class HasFriends
{
friend int ForwardDeclared::IsAFriend(); // C2039 error expected
};
前の例では、クラス名 ForwardDeclared
をスコープに入力しますが、完全な宣言 (具体的には、関数 IsAFriend
を宣言する部分) は不明です。 クラスHasFriends
内のfriend
宣言でエラーが生成されます。
C++11 では、クラスのフレンド宣言には次の 2 つの形式があります。
friend class F;
friend F;
最初の形式では、その名前の既存のクラスが最も内側にある名前空間に見つからなかった場合に、新しいクラス F が導入されます。 C++11: 2 番目のフォームは新しいクラスを導入しません。クラスが既に宣言されている場合に使用でき、テンプレート型パラメーターまたは typedef
a として friend
宣言するときに使用する必要があります。
参照先の型がまだ宣言されていない場合に使用 friend class F
します。
namespace NS
{
class M
{
friend class F; // Introduces F but doesn't define it
};
}
宣言されていないクラス型で使用 friend
すると、エラーが発生します。
namespace NS
{
class M
{
friend F; // error C2433: 'NS::F': 'friend' not permitted on data declarations
};
}
次の例では、friend F
は NS のスコープ外で宣言されている F
クラスを参照しています。
class F {};
namespace NS
{
class M
{
friend F; // OK
};
}
friend F
を使用して、テンプレート パラメーターをフレンドとして宣言します。
template <typename T>
class my_class
{
friend T;
//...
};
friend F
を使用して、typedef をフレンドとして宣言します。
class Foo {};
typedef Foo F;
class G
{
friend F; // OK
friend class F // Error C2371 -- redefinition
};
相互にフレンドである 2 つのクラスを宣言するには、2 番目のクラス全体が最初のクラスのフレンドとして指定される必要があります。 この制限の理由は、2 番目のクラスが宣言された位置でのみコンパイラは個々のフレンド関数を宣言するために十分な情報を得られるためです。
Note
2 番目のクラス全体は最初のクラスへのフレンドである必要がありますが、最初のクラスのどの関数が 2 番目のクラスのフレンドであるかを選択できます。
friend 関数
friend
関数は、クラスのメンバーではありませんが、クラスのプライベートメンバーと保護されたメンバーにアクセスできる関数です。 フレンド関数はクラス メンバーとは見なされません。これらは、特別なアクセス特権が与えられる通常の外部関数です。 フレンドはクラスのスコープ内にありません。また、別のクラスのメンバーでない限り、メンバー選択演算子 (. および ->) を使用して呼び出されることはありません。 friend
関数はアクセスを付与しているクラスで宣言されます。 friend
宣言はクラス宣言内の任意の場所に配置できます。 アクセス制御キーワード (keyword)の影響を受けない。
次に、Point
クラスと ChangePrivate
フレンド関数の例を示します。 friend
関数は、自身がパラメーターとして受け取る Point
オブジェクトのプライベート データ メンバーにアクセスできます。
// friend_functions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Point
{
friend void ChangePrivate( Point & );
public:
Point( void ) : m_i(0) {}
void PrintPrivate( void ){cout << m_i << endl; }
private:
int m_i;
};
void ChangePrivate ( Point &i ) { i.m_i++; }
int main()
{
Point sPoint;
sPoint.PrintPrivate();
ChangePrivate(sPoint);
sPoint.PrintPrivate();
// Output: 0
1
}
フレンドとしてのクラス メンバー
クラス メンバー関数は他のクラスのフレンドとして宣言できます。 次の例を考えてみましょう。
// classes_as_friends1.cpp
// compile with: /c
class B;
class A {
public:
int Func1( B& b );
private:
int Func2( B& b );
};
class B {
private:
int _b;
// A::Func1 is a friend function to class B
// so A::Func1 has access to all members of B
friend int A::Func1( B& );
};
int A::Func1( B& b ) { return b._b; } // OK
int A::Func2( B& b ) { return b._b; } // C2248
前の例では、関数A::Func1( B& )
にのみクラスB
へのアクセスが許可friend
されています。 したがって、プライベート メンバー _b
へのアクセスは、クラス A
の Func1
では正しく、Func2
では正しくありません。
friend
クラスは、メンバー関数がクラスの関数であるfriend
クラス、つまりメンバー関数が他のクラスのプライベート メンバーと保護されたメンバーにアクセスできるクラスです。 friend
クラスの B
宣言が次のようになっていたとします。
friend class A;
その場合、クラス内のすべてのメンバー関数にクラスA
B
へのアクセスが許可friend
されます。 クラスの例を次に friend
示します。
// classes_as_friends2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class YourClass {
friend class YourOtherClass; // Declare a friend class
public:
YourClass() : topSecret(0){}
void printMember() { cout << topSecret << endl; }
private:
int topSecret;
};
class YourOtherClass {
public:
void change( YourClass& yc, int x ){yc.topSecret = x;}
};
int main() {
YourClass yc1;
YourOtherClass yoc1;
yc1.printMember();
yoc1.change( yc1, 5 );
yc1.printMember();
}
フレンドシップは、明示的に指定されていない限り相互に関係しません。 上記の例では、のメンバー関数 YourClass
は YourOtherClass
.
マネージド型 (C++/CLI) には、関数、クラス、friend
またはfriend
インターフェイスをfriend
含めることはできません。
フレンドシップは継承されません。つまり、派生したクラスは YourOtherClass
'プライベート メンバー' にアクセス YourClass
できません。 友情は推移的ではないので、友人 YourOtherClass
であるクラスは 'プライベート メンバー' にアクセス YourClass
できません。
次の図は、4 つのクラス宣言 (Base
、Derived
、aFriend
、anotherFriend
) を示しています。 aFriend
のプライベート メンバー (および Base
が継承した可能性があるすべてのメンバー) に直接アクセスできるのは、Base
クラスだけです。
この図は、anotherFriend クラスが、フレンド クラス aFriend クラスの基底クラスとフレンド関係を持っていないことを示しています。 クラス aFriend はクラス Base によってフレンド化されますが、派生クラスが Base から継承されている場合でも、クラス Derived とのフレンド関係はありません。 これは、継承が派生クラスに基底クラスと同じフレンドがあることを意味しないことを示しています。
インライン friend
定義
フレンド関数は、クラス宣言内で (関数本体を指定して) 定義できます。 これらの関数はインライン関数です。 メンバー インライン関数と同様に、すべてのクラス メンバーが表示された直後、クラス スコープが閉じられる前 (クラス宣言の最後) に定義されたかのように動作します。 クラス宣言内で定義されているフレンド関数は、それを囲んでいるクラスのスコープ内にあります。
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示