将数据和处理数据的函数封装在一起,构成类,实现了数据的隐藏,无疑是面向对象程序设计的一大优点。但是有时候封装不是绝对的。
友元函数提供了不同类或对象的成员函数之间、类的成员函数和一般函数之间进行数据共享的机制。通俗的说,友元关系就是一个类主动声明哪些类或函数是它的朋友,进而给它们提供对本类的访问特性。也就是说,通过友元关系,一个普通函数或者类的成员函数可以访问封装于另外一个类中的数据。
从一定程度上讲,友元是对数据隐藏和封装的破坏,但是为了数据共享,提高程序的效率和可读性,很多情况下这种小的破坏是必要的。
在一个类中,利用关键字friend将其它函数或类声明为友元。如果友元是一般函数或类的成员函数,称为友元函数。如果友元是一个类,则称为友元类。友元类的所有成员函数都自动称为友元函数。
友元函数
友元函数是在类中用关键字friend修饰的非成员函数,可以是一个普通的函数,或是其它类的成员函数。
虽然它不是本类的成员函数,却在它的函数体中却可以通过对象名访问类的私有成员和保护成员。
例如:使用友元函数计算两点之间的距离,
#include <iostream> #include <cmath> using namespace std; //使用友元函数计算两点之间的距离 class Point{ public: Point(int xx = 0, int yy = 0) { X = xx; Y = yy;} int GetX() {return X;} int GetY() {return Y;} friend float fDist( Point &a, Point &b ); private: int X, Y; }; float fDist(Point &p1, Point &p2){ double x = double(p1.X - p2.X);//通过对象访问私有数据成员,而不是必须使用Getx()函数 double y = double(p1.Y - p2.Y); return float(sqrt(x*x + y*y)); } int main(){ Point p1(1, 1), p2(4, 5); cout << "the distance is:"; cout << fDist(p1, p2) << endl;//计算两点之间的距离 return 0; }
可以看到在友元函数fDist()中通过对象名直接访问了Point类的私有数据成员X和Y。
友元类
同友元函数一样,一个类可以将另一个类声明为友元类。若A类为B类的友元函类,则A类中的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员。例如:
class A{ public: int GetX() { return x; } friend class B;//B类是A类的友元类 //其它成员略 private: int x; }; class B{ public: void set(int i); //其他成员略 private: A a; }; void B :: set(int i){ a.x = i;//由于B类是A类的友元类,所以在B的成员函数中可以访问A类对象的私有成员 }关于友元,需要注意的点:
友元关系不能传递
友元关系是单向的
有云关系不能被继承