类具备封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员,非成员函数能够访问类中的公有成员,但是假如将数据成员都定义为公有的,这又破坏了隐藏的特性。另外,应该看到在某些情况下,特别是在对某些成员函数多次调用时,由于参数传递,类型检查和安全性检查等都需要时间开销,而影响程序的运行效率。
为了解决上述问题,提出一种使用友元的方案。
友元可以是个函数,该函数被称为友元函数;友元也可以是个类,该类被称为友元类。
友元函数:
友元函数是一种定义在类外部的普通函数,但需要在类体内进行说明,为了和该类的成员函数加以区别,在说明时前面要加以关键字friend。友元不是成员函数,但是它能够访问类中的私有成员。友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率,但矛盾的是,即使是最大限度的保护,同样也破坏了类的封装特性,这即是友元的缺点,在CPU速度越来越快的今天,并不推荐使用它。
友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看和普通函数相同,即在定义上和调用上和普通函数相同。
#include<iostream>
using namespace std;
class Date
{
private:
int A,B;
public:
Date(int,int);
friend void print(Date&); //友元函数的声明
};
Date::Date(int a,int b)
{
A=a,B=b;
}
void print(Date& D) //友元函数的定义(无需指出所属的类)
{
cout<<D.A<<" "<<D.B<<endl; //要使用成员操作符(.)
}
int main()
{
Date D(1,2);
print(D);
return 0;
}
友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
友元类:
友元还可以是类,即一个类能够作另一个类的友元。当一个类作为另一个类的友元时,就意味着这个类的任何成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。
定义友元类的语句格式如下: friend class 类名;
其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类B是类A的友元类:
class A
{
…
public:
friend class B;
…
};
经过以上说明后,类B的所有成员函数都是类A的友元函数,能存取类A的私有成员和保护成员。
使用友元类时注意:
(1)友元关系不能被继承。
(2)友元关系是单向的,不具有交换性。若类B是类A的友元,但类A不一定是类B的友元,要看在类中是否有相应的声明。
(3)友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的声明。
注意事项:
1.友元可以访问类的私有成员。
2.友元只能在类的内部声明,但可以在类中的任何地方声明,一般放在类定义的开始或结尾。
3.友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
4.类必须将重载函数集中每一个要设为友元的函数都声明为友元。
5.友元关系不能被继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。