采用类的机制后实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,成员函数一般定义为公有的,依此提供类与外界间的通信接口。但是,有时需要定义一些函数,这些函数不是类的一部分,但又需要频繁地访问类的数据成员, 这时可以将这些函数定义为该 函数的友元函数。除了友元函数外,还有友元类, 两者统称为友元。友元的作用是提高了程序的运行效率(即减少了类型检查和 安全性检查等都需要时间开销),但它破坏了类的封装 性和隐藏性,使得非成员函数可以访问类的私有成员。 友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元 类。
友元函数没有this指针。this指针是在指向类成员本身,但是友元函数并不在类里面,而是在类外面
1、友元函数
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上 关键字 friend,其格式如下:
friend 类型 函数名(形式参数);
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
2、友元类
#if 1
#include<iostream>
#include<math.h>
using namespace std;class Point;
class PointManager {
public:double PointDistance3(Point &p1, Point &p2);
};class Point {
public://声明全局函数 PointDistance2 是我类Point的一个友元函数friend double PointDistance2(Point &p1, Point &p2); //写在哪个位置都okfriend double PointManager::PointDistance3(Point &p1, Point &p2); //写在哪个位置都okPoint(int x, int y) {this->m_x = x;this->m_y = y;
}int get_x() {return m_x;}int get_y() {return m_y;}private:int m_x;int m_y;};
double PointDistance1(Point &p1, Point &p2) {double dis;//int dd_x = p1.m_x - p2.m_x; 编译错误int dd_x = p1.get_x() - p2.get_x();int dd_y = p1.get_y() - p2.get_y();dis = sqrt(dd_x*dd_x + dd_y*dd_y);return dis;
}
double PointDistance2(Point &p1, Point &p2) { //声明为友元函数double dis;int dd_x = p1.m_x - p2.m_x;int dd_y = p1.m_y - p2.m_y;dis = sqrt(dd_x*dd_x + dd_y*dd_y);return dis;
}
# if 0
//此种写法错误
//改为友元函数类内申明 类外实现
class PointManager {
public:double PointDistance3(Point &p1, Point &p2) {double dis;int dd_x = p1.m_x - p2.m_x;int dd_y = p1.m_y - p2.m_y;dis = sqrt(dd_x*dd_x + dd_y*dd_y);return dis;}
};
#endif//类中友元函数
double PointManager::PointDistance3(Point &p1, Point &p2) {double dis;int dd_x = p1.m_x - p2.m_x;int dd_y = p1.m_y - p2.m_y;dis = sqrt(dd_x*dd_x + dd_y*dd_y);return dis;
}void test01() {Point p1(1, 2), p2(2, 2);int dis = PointDistance1(p1, p2);cout << "dis:" << dis << endl; //dis:1
}void test02() {Point p1(1, 2), p2(2, 2);PointManager pm;cout << pm.PointDistance3(p1, p2) << endl; //1
}
int main(void) {//test01();test02();return 0;
}
#endif
3、论友元
声明位置:
友元声明以关键字 friend 开始,它只能出现在类定义中。因为友元不是授权类的成员,所以它不受其所在类的声明区域 public private 和 protected 的影 响。通常我们选择把所有友元声明组织在一起并放在类头之后.
友元的利弊:
友元不是类成员,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问 类的私有成员。 不过,类的访问权限确实在某些应用场合显得有些呆板,从而容 忍了友元这一特别语法 现象。
注意事项:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类 B 是类 A 的友元,类 A 不一定是类B 的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类 B 是类 A 的友元,类 C 是 B 的友元,类 C 不一定 是类 A 的友元,同样要看类中是否有相应的声明。