写在前面
这一篇博客简单的记录一下我对于友元的理解。友元可以是个函数,就称为友元函数,也可以是一个类,就称为友元类。类,(这个我还没有专门整理),具有封装信息与提供结构的特性。public可以为外部提供调用接口,private则隐藏与类相关的数据方法等,起到抽象对象的作用。所以,只有内的成员函数才能访问类的私有成员,程序中其他的函数是无法访问私有成员变量的,但是能够访问类中的公有变量或者函数。
有些时候希望能有外部函数访问类的成员,按照之前所说,就需要类的成员定义为公有的,但是这样会破坏类的封装特性。此外,由于对某些成员函数多次调用时,参数传递、类型检查和安全性检查等都需要时间开销,这回导致程序运行效率的降低。
所以为了解决这些问题,可以采用友元的解决方案。
友元(friend)机制
友元(friend)机制允许一个类将对非公有成员的访问权授予一个指定的函数或者类。友元通常是一种定义在类外部的普通函数或者类,但是他需要在要访问的非公有成员的类中进行声明。那么为了与该类的其他成员区分,会添加关键字friend。
注意,友元不是类的成员,而是其他函数或者类能访问该类的私有成员。
参考文献:
友元函数
下面来看一个例子,通过它能对友元函数有一个直观的印象。
#include<iostream>
#include<math.h>
using namespace std;
class Point{
public:
Point(double xx, double yy){ x=xx; y=yy; }
void Getxy();
friend double Distance(Point &a, Point &b);
private:
double x, y;
};
void Point::Getxy(){
cout << "(" <<x<< "," <<y<< ")" << endl;
}
double Distance(Point &a, Point &b){
double dx = a.x-b.x;
double dy = a.y-b.y;
return sqrt(dx*dx + dy*dy);
}
int main(){
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.Getxy();
p2.Getxy();
double dis = Distance(p1, p2);
cout << "Distance is " <<dis<< endl;
return 0;
}
在这个程序中:
- 首先定义了一个Point类。Point类中有:构造函数Point(double xx, double yy){…}、公有成员函数Getxy(),与私有成员变量x与y,此外声明了一个友元函数Distance(Point &a, Point &b)();
- 然后在类外部,实现了成员函数Getxy(),该函数访问了类的私有成员变量x与y;
- 接着实现了Point类中声明的友元函数Distance(Point &a, Point &b),该函数访问了这两个Point类的私有成员变量x与y。
从政程序中,不难发现,函数Distance本来是外部函数,通过在类Point中,friend修饰声明,即可访问一般由类成员函数才能访问的到的私有成员变量。
友元类
友元类的声明方法与友元函数如出一辙。自己写了个例子,希望大家能看得懂:
#include<iostream>
using namespace std;
class Boy{
public:
Boy(double height, int age, int weight){
bheight = height;
bage = age;
bweight = weight;
}
void GetBoy();
friend class Girl;
private:
double bheight;
int bage;
int bweight;
};
class Girl{
public:
Girl(double height, int age, int weight){
gheight = height;
gage = age;
gweight = weight;
}
void GetGirl();
void GetBoyFriend(Boy &b);
private:
double gheight;
int gage;
int gweight;
};
void Boy::GetBoy(){
cout<<"Boy's Height, age and weight is: " << bheight << " " << bage << " " << bweight << endl;
}
void Girl::GetGirl(){
cout<<"Girl's Height, age and weight is: " << gheight << " " << gage << " " << gweight << endl;
}
void Girl::GetBoyFriend(Boy &b){
cout<<"BoyFriend's Height, age and weight is: " << b.bheight << " " << b.bage << " " << b.bweight << endl;
}
int main(){
Boy Ida(180.0, 22, 70);
Girl Jenny(170.0, 20, 50);
Ida.GetBoy();
Jenny.GetGirl();
Jenny.GetBoyFriend(Ida);
return 0;
}
在这个程序中,定义了两个类,两个类都有对应的构造函数、getXXX()函数(用来输出各自类中私有成员变量)与3个私有成员变量,但是Boy类中声明了一个友元类Girl,类Girl中也有一个成员函数getBoyFriend来访问Boy中的成员变量。
通过友元,类Girl的成员函数getBoyFriend可以获取类Boy中的私有成员变量。
注意,刚开始并没有区分两个类的成员变量的名称,导致输出结果出错,后来进行了区分,结果就没有问题了。目前还没想明白。
使用友元类时注意:
- 友元关系不能被继承。
- 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
- 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
- 友元可以访问类的私有成员。
- 只能出现在类定义内部,友元声明可以在类中的任何地方,一般放在类定义的开始或结尾。
- 友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。
- 类必须将重载函数集中每一个希望设为友元的函数都声明为友元。
- 友元关系不能继承,基类的友元对派生类的成员没有特殊的访问权限。如果基类被授予友元关系,则只有基类具有特殊的访问权限。该基类的派生类不能访问授予友元关系的类。
写在后面
这个博客学习了友元(friend)机制,其实就是给外部的类或者函数提供了一种能访问类的私有成员变量的机制。