奔放的友元
C++中采用类的机制后实现了数据的隐藏与封装, 类的数据成员一般定义为私有成员, 成员函数一般定义为公有的。依此提供类与外界间的通信接口。但是, 有时需要定义一些函数, 这些函数不是类的一部分, 但又需要频繁地访问类的数据成员, 这时可以将这些函数定义为该类的友元函数。
除了友元函数外, 还有友元类, 两者统称为友元。
友元的作用是提高了程序的运行效率(即减少了类型和安全性检查及调用的时间开销), 但它破坏了类的封装性和隐藏性, 使得非成员函数可以访问类的私有成员。
0、两点特性
(1)同类之间无私处
一个类可以访问本类所有对象的私有成员。(同族类的对象之间没有隐私,所有数据皆可访问)
(2)异类之间有友元
友元打破了外部访问类中的 private 私有数据成员的权限。友元内没有this指针,所有数据得通过对象来访问。
1、友元函数
全局函数作友元函数。
友元函数(全局函数):求两点之间的距离
class Point
{
public:
Point(double a, double b)
:x(a),y(b){} //构造 输入一个点的横纵坐标
friend double dis (Point t1,Point t2); //全局友元函数声明
private:
double x,y;
};
double dis (Point & t1,Point & t2) //函数体
//定义为友元函数之后 dis函数可以通过Point的对象访问Point的私有数据。
{
double dx = t1.x - t2.x;
double dy = t1.y - t2.y;
return sqrt(dx*dx+dy*dy);
}
int main()
{
Point t1(0,0);
Point t2(3,4);
double r = dis(t1,t2);
cout<<r<<endl;
return 0;
}
成员函数作友元函数
两个类的成员函数或用到的数据会交叉,所以声明也是个问题。
前向声明, 是一种不完全型声明, 即只需提供类名(无需提供类实现)即可。
友元:前向声明 只能限用于 指针或引用。
#include <iostream>
#include <math.h>
using namespace std;
//友元函数:求两点之间的距离
class Point; //前向声明 解决 class pointManagement 里边应用的Point 引用。
class pointManagement
{
public:
double dis (Point &t1,Point &t2);
//其函数体 因为用到了Ponit的数据 so放在 class Ponit 后边
};
class Point
{
public:
Point(double a, double b)
:x(a),y(b){} //构造 输入一个点的横纵坐标
friend double pointManagement::dis(Point & t1,Point & t2);//用谁的数据在谁里边声明友元函数
private:
double x,y;
};
double pointManagement:: dis (Point &t1,Point &t2) //求两点距离
{
double dx = t1.x - t2.x;
double dy = t1.y - t2.y;
return sqrt(dx*dx+dy*dy);
}
int main()
{
Point t1(0,0);
Point t2(3,4);
pointManagement pm;
double r = pm.dis(t1,t2); //通过对象去访问
cout<<r<<endl;
return 0;
}
2、友元类
当希望一个类中所有成员函数, 均可存取另一个类的私有成员时, 方便起见,可以将该类声明为另一类的友元类。
友元类, 使异类之间的成员函数访问数据更加简单,也就是将所有的友元类的成员函数及私有成员公开化了。方便操作(不用多次声明&调用了)。但是会导致封装破坏的面积扩大化。
把a声明为b的友元,就可以通过b的变量访问b的 private 数据成员。
如下: 把pm声明为p的友元,就可以在pm的类里 通过p的变量访问p的私有数据成员。(通过谁的对象去访问)
#include <iostream>
#include <math.h>
using namespace std;
class Point
{
friend class PointManagement;// 声明友元类
public:
Point(double a, double b)
:x(a),y(b){} //构造 输入一个点的横纵坐标
private:
double x,y;
};
class PointManagement
{
public:
double getDistance (Point &t1,Point &t2)
{
double dx = t1.x - t2.x;
double dy = t1.y - t2.y;
return sqrt(dx*dx+dy*dy);
}
};
int main ()
{
Point t1(0,0),t2(3,4);
PointManagement pm;
double r = pm.getDistance(t1,t2);
cout<<r<<endl;
}
友元利弊:
友元不是类成员,但是它可以通过对象访问类中的私有成员。 友元的作用在于提高程序的运行效率, 但是它破坏了类的封装性和隐藏性, 使得非成员函数可以访问类的私有成员。-->友元是使对类的更加自由奔放的做法。
注意:
友元关系不能被继承。
单向性、不可交换性、 不可传递性。
//友元关系是单向的,不具有交换性。若类 B 是类 A 的友元,类 A 不一定是类 B的友元,要看在类中是否有相应的声明。
//友元关系不具有传递性。若类 B 是类 A 的友元,类 C 是 B 的友元,类 C 不一定是类 A 的友元,同样要看类中是否有相应的声明。