参考《c++ Primer Plus》 第6版15.1ios
C++控制对类对象私有部分的访问,在外部没法直接访问类的私有或保护成员。一般,公有类方法提供惟一的访问途径。有时这种限制太严格,不适合特定的编程问题。因此C++提供了友元这种形式,经过让函数或类成为类的友元,能够赋予该函数或类与类的成员函数具备相同的访问权限。c++
友元的做用在于提升程序的运行效率(即减小了类型检查和安全性检查等都须要的时间开销),可是,它破坏了类的封装性和隐藏性,使得非成员函数能够访问类的私有成员。编程
(1)友元函数安全
(2)友元类函数
(3)友元成员函数this
在类定义体中由关键字friend加以修饰说明的非成员函数spa
#include <iostream> using namespace std; 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。 int main() { Window winA(10,10,300,300); cout <<"Window Area is "<< endl; cout <<"Window Area square: "<< Area(winA)<< endl; return 0; }
运行结果:设计
Window Area is Window Area square: 90000
友员函数与成员函数在编程方面的不一样点:
① 友员函数在类体内应该采用friend加以限定,但成员函数不须要。
② 友员函数体在类体外不须要采用"类名::"加以限定。
③ 调用它时不须要采用"对象名.成员名"方式,而是直接调用它。
④ 因为友员函数不是成员函数,于是无this指针,在函数体中访问对象中的成员时必须经过对象名(可将形参定义为引用),而在成员函数体内能够直接访问成员数据。指针
注释:code
类的友元函数是非成员函数,其访问权限与成员函数相同。
能够将类做为友元,友元类的全部方法均可以访问原始类的私有成员和保护成员。
以下 friend class Remote; 声明Remote为Tv类的友元类:
//tv.h -- Tv and Remote classes #ifndef TV_H_ #define TV_H_ class Tv { public: friend class Remote; //Remote can access Tv private parts enum State{Off,On}; enum {MinVal,MaxVal=20}; enum {Antenna,Cable}; enum {TV,DVD}; Tv(int s=Off,int mc=125):state(s),volume(5),maxchannel(mc),channel(12),mode(Cable),input(TV) {} void onoff() {state=(state==On)?Off:On;} bool ison() const {return state==On;} bool volup(); bool voldown(); void chanup(); void chandown(); void set_mode() {mode=(mode==Antenna)?Cable:Antenna;} void set_input() {input=(input==TV)?DVD:TV;} void settings() const; //display all settings private: int state; int volume; int maxchannel; int channel; int mode; int input; }; class Remote { private: int mode; public: Remote(int m = Tv::TV): mode(m){}; bool volup(Tv &t){return t.volup();} bool voldown(Tv & t){return t.voldown();} void onoff(Tv & t){t.onoff();} void chanup(Tv & t){t.chanup();} void chandown(Tv & t){t.chandown();} void set_chan(Tv & t,int c){t.channel=c;} void set_mode(Tv & t){t.set_mode();} void set_input(Tv & t){t.set_input();} };
在Remote类中,只有set_channel(Tv & tv, int ch)方法直接访问Tv类的私有成员,因此能够选择只让这个方法成为类的友元,而没必要让Remote整个类成为友元。不过这么作必须当心排列各类声明和定义的顺序。
让Remote::set_channel()成为Tv类的友元方法是,在Tv类中将其声明为友元:
//tvfm.h #ifndef TVFM_H_ #define TVFM_H_ class Tv; class Remote { public: enum State{Off,on}; enum {MinVal,MaxVal=20}; enum {Antenna,Cable}; enum {TV,DVD}; private: int mode; public: Remote(int m=TV):mode(m) {} bool volup(Tv &t); bool voldown(Tv & t); void onoff(Tv & t); void chanup(Tv & t); void chandown(Tv & t); void set_mode(Tv & t); void set_input(Tv & t); void set_chan(Tv & t,int c); }; class Tv { public: friend void Remote::set_chan(Tv & t,int c); enum State{Off,On}; enum {MinVal,MaxVal=20}; enum {Antenna,Cable}; enum {TV,DVD}; Tv(int s=Off,int mc=125):state(s),volume(5),maxchannel(mc),channel(12),mode(Cable),input(TV) {} void onoff() {state=(state==On)?Off:On;} bool ison() const {return state==On;} bool volup(); bool voldown(); void chanup(); void chandown(); void set_mode() {mode=(mode==Antenna)?Cable:Antenna;} void set_input() {input=(input==TV)?DVD:TV;} void settings() const; //display all settings private: int state; int volume; int maxchannel; int channel; int mode; int input; }; //Remote methods as inline functions inline bool Remote::volup(Tv & t){return t.volup();} inline bool Remote::voldown(Tv & t){return t.voldown();} inline void Remote::onoff(Tv & t){t.onoff();} inline void Remote::chanup(Tv & t){t.chanup();} inline void Remote::chandown(Tv & t){t.chandown();} inline void Remote::set_mode(Tv & t){t.set_mode();} inline void Remote::set_input(Tv & t){t.set_input();} inline void Remote::set_chan(Tv & t,int c) {t.channel=c;} #endif
① 在封装和快速性两方面合理选择----OOP中类的主要优势是能够实现数据隐藏与保护,即不容许非成员函数对它访问,这样能够提升数据使用的安全性。但在访问数据的效率方面则降低(由于正常时应该经过public型的方法来访问)。但在某些应用场合下,非成员函数体中须要经过对象名直接访问类中的private成员,以达到高速高效率地访问数据,这能够经过友员函数来实现。
② 有些函数须要放在类的外面或者类设计完之后再加以补充的,此时可能不能设计为类中的成员函数,可是又须要访问类中的私有成员。