在某些情况下,类授予成员级对不是类成员的函数或单独类中的所有成员的访问权限非常有用。 这些免费函数和类称为 好友,由 friend 关键字标记。 只有类实现者可以声明其好友是谁。 函数或类不能将自身声明为任何类的友元。 在类定义中 friend ,使用非member 函数或其他类的关键字和名称授予它对类的私有和受保护成员的访问权限。 在模板定义中,类型参数可以声明为 .friend
语法
friend-declaration:
friend
function-declaration
friend
function-definition
friend
elaborated-type-specifier
;;
friend
simple-type-specifier
;
friend
typename-specifier
;
friend 声明
如果声明 friend 了以前未声明的函数,该函数将导出到封闭的非类范围。
在 friend 声明中声明的函数被视为使用关键字声明 extern 的函数。 有关详细信息,请参阅 extern。
尽管具有全局范围的函数可以在原型之前声明为 friend 函数,但在其完整类声明的外观之前,成员函数不能声明为 friend 函数。 以下代码演示了此类声明如何失败:
class ForwardDeclared; // Class name is known.
class HasFriends
{
friend int ForwardDeclared::IsAFriend(); // C2039 error expected
};
前面的示例将类名 ForwardDeclared 输入到作用域中,但完整的声明(具体而言,声明函数 IsAFriend的部分)未知。
friend类HasFriends中的声明生成错误。
在 C++11 中,类有两种形式的友元声明:
friend class F;
friend F;
第一个窗体在最内部的命名空间中未找到该名称的现有类,则引入新的类 F。
C++11:第二种形式不引入新类;当类已声明时,可以使用它,并且必须在声明模板类型参数或 typedef 作为参数 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 指 F 在 NS 范围之外声明的类。
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
};
若要声明两个类是彼此的朋友,必须将整个第二个类指定为第一个类的友元。 此限制的原因是编译器有足够的信息来仅在声明第二个类时声明单个友元函数。
注释
虽然整个第二类必须是第一类的朋友,但你可以选择第一类中的哪些函数将是第二类的朋友。
friend 函数
friend函数是一个函数,该函数不是类的成员,但有权访问该类的私有成员和受保护的成员。 友元函数不被视为类成员;它们是提供特殊访问权限的正常外部函数。 好友不在类范围内,除非它们是另一个类的成员,否则不会使用成员选择运算符 (和 ->) 调用它们。 函数 friend 由授予访问权限的类声明。 可以在 friend 类声明中的任意位置放置声明。 它不受访问控制关键字的影响。
下面的示例显示了一个 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& ) 授予 friend 对类 B的访问权限。 因此,对私有成员_b的访问在类A中Func1是正确的,但不在类中Func2。
类 friend 是一个类,其成员函数都是 friend 类的函数,即其成员函数有权访问其他类的私有成员和受保护的成员。
friend假设类B中的声明是:
friend class A;
在这种情况下,类 A 中的所有成员函数都将被授予 friend 对类 B的访问权限。 以下代码是 类的示例 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();
}
除非明确指定为友谊,否则友谊不是相互的。 在上面的示例中,无法访问其私有成员的成员YourOtherClass函数YourClass。
托管类型(在 C++/CLI 中)不能有任何 friend 函数、 friend 类或 friend 接口。
友谊不是继承的,这意味着派生自 YourOtherClass 的类无法访问 YourClass's private members。 友谊不是可传递的 YourOtherClass ,所以那些是不能访问 YourClass私人成员的朋友的班级。
下图显示了四个类声明: Base、 Derived、 aFriend和 anotherFriend。 只有类 aFriend 可以直接访问 (以及可能继承的任何成员) 的 Base 私有成员 Base 。
该图显示,另一个Friend的类与类基没有朋友关系,好友类是朋友。 Class aFriend 是类 Base 的友元,但它与类 Derived 没有友元关系,即使类 Derived 继承自 Base。 这表明继承并不意味着派生类与基类具有相同的朋友。
内联 friend 定义
可以在类声明内定义(给定函数体)的友元函数。 这些函数是内联函数。 与成员内联函数一样,它们的行为就像在看到所有类成员之后立即定义,但在类范围关闭之前(在类声明的末尾)。 类声明内定义的友元函数位于封闭类的范围内。