友员函数跟友元类是友员机制的主要内容。
1、友员函数
1.1、友员函数:
在类定义体中由关键字friend加以修饰说明的非成员函数,在它的函数体中能够通过该类的对象来访问类中的private/protected成员。
class Window {
public:
Window(int x, int y, int h, int w) {
X=x , Y=y , H=h , W=w ; } friend long Area(Window & WinObj) ; //在类中声明出友员函数的原型 int getH() {
return H ; } int getW() {
return W ; } private:
int X,Y,H,W ; }; long Area(Window & WinObj) //在类外定义出友员函数的函数体 {
return (long)WinObj.H*WinObj.W ; } //实现通过对象访问类中的private成员,因为对窗口的面积的计算最简单的方式应该是H*W。 void main() {
Window winA(10,10,300,300) ; cout <<"Window Area is "<<Area(winA)<<endl;
} //要点:可以将友员函数的定义体直接放在类体中,形成内联函数;友员函数在类中的摆放位置可以在public或者private之后,
//因为他不是这个类的成员,故其不受这个类的访问控制限制,其编程效果相同(类中的访问控制对它无效)。 class Window {
private:
int X,Y,H,W ; friend long Area(Window & WinObj) { } };
1.2、为什么需要友员函数
①
在封装和快速性两方面合理选择----OOP中类的主要优点是可以实现数据隐藏与保护,即不允许非成员函数对它访问,这样可以提高数据使用的安全性。但在访问数据的效率方面则下降(因为正常时应该通过public型的方法来访问)。但在某些应用场合下,非成员函数体中需要通过对象名直接访问类中的private成员,以达到高速高效率地访问数据,这可以通过友员函数来实现。(例如被重载的操作符,他不是类的成员,但是他经常会访问类的私有成员)(尽管这些重载的操作符不是类的成员但是特他们仍然是类的接口的组成部分)。
friend long Area(Window & WinObj) {
//非成员函数体中需要通过对象名访问private成员 return (long)WinObj.H*WinObj.W ; //否则应该(long)WinObj.getH()*WinObj.getW(); }
②
有些函数需要放在类的外面或者类设计完以后再加以补充的,此时可能不能设计为类中的成员函数,但是又需要访问类中的私有成员。
1.3、友员函数与成员函数在编程方面的不同点
① 友员函数在类体内应该采用friend加以限定,但成员函数不需要。
② 友员函数体在类体外不需要采用"类名::"加以限定。
③ 调用它时不需要采用"对象名.成员名"方式,而是直接调用它。
④
由于友员函数不是成员函数,因而无this指针,在函数体中访问对象中的成员时必须通过对象名(可将形参定义为引用),而在成员函数体内可以直接访问成员数据。
1.4、友员函数与一般函数(非成员函数)在编程方面的不同点
①
友员函数在类体内应该采用friend加以限定,但非成员函数不需要在类中声明。
②
在友员函数体内可以利用对象访问类中的private成员,但非成员函数则不能。
2、友员类:
2.1、含义:一个类为另一个类的友员类---此类的所有成员函数都能访问对方类的私有成员。
2.2、友员类的定义:将此类名在另一个类中使用friend加以修饰说明。
class MyClass ; //类的引用性前向说明 class Window {
public: friend class MyClass ; //类名的使用 private:
int X,Y,H,W ; }; class MyClass //类的定义体 {
public: void ShowArea() {
cout <<"Area is" <<ednl;
} private: Window win ; };
2.3、应用目的:在类的封装和共享两方面合理选择---类的主要优点是实现数据隐藏与保护,从而将数据与方法相互组合产生独立的代码块,但这样将使各个类相互孤立,无法实现类之间的共享。但在应用需求中可能要实现多个类之间的共享,这可以采用友元类的方式来实现。