面向对象编程的类的设计机制实现了数据的隐藏与封装,类的成员变量通常定义为私有成员,成员函数通常定义为公有的,是类与外部的通讯接口。在实践中,类外的某些函数须要频繁地访问类的成员变量,能够将类外的函数定义为类的友元函数。除了友元函数外,还有友元类,二者统称为友元。友元的做用是提升了程序的运行效率(即减小了类型检查和安全性检查等都须要时间开销),但友元破坏了类的封装性和隐藏性,使得非类的成员函数能够访问类的私有成员。
友元是C++语言中的一种关系,友元关系发生在函数与类之间或者类与类之间。友元关系是单向的,不能传递。
与类有友元关系的函数称为友元函数,与类有友元关系的类称为友元类。ios
友元的特性以下:
A、在类中以friend关键字声明友元
B、类的友元能够是其它类或具体函数
C、友元不是类的一部分
D、友元不受类中访问级别的限制
E、友元能够直接访问具体类的全部成员
F、友元关系不能被继承
G、友元关系是单向的,不具交换性
H、友元关系不具备传递性编程
友元的本质,是让其它不属于本类的成员(全局函数,其它类的成员函数,其它类),成为本类的成员而具有本类成员的属性。安全
友元函数是能够直接访问类的私有成员的非成员函数,是定义在类外的函数,能够是不属于任何类的全局函数或是其它类的成员函数,但须要在类的定义中加以声明。ide
全局函数做为类的友元声明时只需在友元的名称前加上关键字friend,其格式以下:friend 类型 函数名(形式参数);
一个函数能够是多个类的友元函数,只须要在各个类中分别声明。函数
#include <iostream> #include <cmath> using namespace std; class Point { public: Point(double x = 0, double y = 0) { this->x = x; this->y = y; } void printPoint() { cout << "(" << x << "," << y << ")"; } //友元函数声明 friend double getDistance(const Point &a, const Point &b); private: double x; double y; }; double getDistance(const Point &a, const Point &b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx*dx + dy*dy); } int main(int argc, char *argv[]) { Point a(0,0); Point b(1,8); cout << "Point"; a.printPoint(); cout << " and Point"; b.printPoint(); cout << " has distance at "<< getDistance(a, b) << endl; return 0; }
类成员函数做为类的友元声明时只需在友元的名称前加上关键字friend,其格式以下:friend 类型 类名::函数名(形式参数);
一个函数能够是多个类的友元函数,只须要在各个类中分别声明。学习
#include <iostream> #include <cmath> using namespace std; class Point; class ManagerPoint { public: double getDistance(const Point &a, const Point &b); }; class Point { public: Point(double x = 0, double y = 0) { this->x = x; this->y = y; } void printPoint() { cout << "(" << x << "," << y << ")"; } //友元函数声明 friend double ManagerPoint::getDistance(const Point &a, const Point &b); private: double x; double y; }; double ManagerPoint::getDistance(const Point &a, const Point &b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx*dx + dy*dy); } int main(int argc, char *argv[]) { ManagerPoint manager; Point a(0,0); Point b(1,8); cout << "Point"; a.printPoint(); cout << " and Point"; b.printPoint(); cout << " has distance at "<< manager.getDistance(a, b) << endl; return 0; }
上述代码中使用了类的前向声明。前向声明,是一种不彻底型(forward declaration)声明,即只需提供类名(无需提供类实现)便可。前向声明功能有限:
A、不能定义类的对象。
B、能够用于定义指向这个类型的指针或引用。
C、用于声明(不是定义)使用该类型做为形参或者返回类型的函数。this
友元类的全部成员函数都是另外一个类的友元函数,均可以访问另外一个类中的隐藏信息(包括私有成员和保护成员)。当但愿一个类能够访问另外一个类的私有成员、保护成员时,能够将该类声明为另外一类的友元类。
定义友元类的语句格式以下:friend class 类名;
friend和class是关键字,类名必须是程序中的一个已定义的类。spa
#include <iostream> #include <cmath> using namespace std; class Point; class ManagerPoint { public: double getDistance(const Point &a, const Point &b); }; class Point { public: Point(double x = 0, double y = 0) { this->x = x; this->y = y; } void printPoint() { cout << "(" << x << "," << y << ")"; } //友元类声明 friend class ManagerPoint; private: double x; double y; }; double ManagerPoint::getDistance(const Point &a, const Point &b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx*dx + dy*dy); } int main(int argc, char *argv[]) { ManagerPoint manager; Point a(0,0); Point b(1,8); cout << "Point"; a.printPoint(); cout << " and Point"; b.printPoint(); cout << " has distance at "<< manager.getDistance(a, b) << endl; return 0; }
ManagerPoint类的全部成员函数都是类Point的友元函数,能访问类Point的私有成员和保护成员。