http://blog.csdn.net/insistgogo/article/details/6608672
http://www.cnblogs.com/fzhe/archive/2013/01/05/2846808.html
1、为什么要引入友元函数:在实现类之间数据共享时,减少系统开销,提高效率
具体来说:为了使其他类的成员函数直接访问该类的私有变量
即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数
优点:能够提高效率,表达简单、清晰
缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。
2、什么时候使用友元函数:
1)运算符重载的某些场合需要使用友元。
2)两个类要共享数据的时候
3、怎么使用友元函数
友元函数的参数
因为友元函数没有this指针,则参数要有三种情况:
1、 要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)
2、 要访问static成员或全局变量时,则不需要对象做参数
3、 如果做参数的对象是全局对象,则不需要对象做参数
友元函数的位置
因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。
友元函数的调用
可以直接调用友元函数,不需要通过对象或指针
友元函数的分类
根据这个函数的来源不同,可以分为三种方法:
1、普通函数友元函数:
a) 目的:使普通函数能够访问类的友元
b) 语法:声明位置:公有私有均可,常写为公有
声明: friend + 普通函数声明
实现位置:可以在类外或类中
实现代码:与普通函数相同(不加不用friend和类::)
调用:类似普通函数,直接调用
2、类Y的所有成员函数都为类X友元函数—友元类
a)目的:使用单个声明使Y类的所有函数成为类X的友元
它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能
具体来说:
前提:A是B的友元(=》A中成员函数可以访问B中有所有成员,包括私有成员和公有成员--老忘)
则:在A中,借助类B,可以直接使用~B . 私有变量~的形式访问私有变量
b)语法:声明位置:公有私有均可,常写为私有(把类看成一个变量)
声明: friend + 类名---不是对象啊
调用:
3、类Y的一个成员函数为类X的友元函数
a)目的:使类Y的一个成员函数成为类X的友元
具体而言:而在类Y的这个成员函数中,借助参数X,可以直接以X。私有变量的形式访问私有变量
b)语法:声明位置:声明在公有中 (本身为函数)
声明:friend + 成员函数的声明
调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制
4、在模板类中使用友元operator<<(对<<运算符的重载)
a)使用方法:
在模板类中声明:
friend ostream& operator<< <>(ostream& cout,const MGraph<VexType,ArcType>& G);
在模板类中定义:
template<class VexType,class ArcType> ostream& operator<<(ostream& cout,const MGraph<VexType,ArcType>& G) { //函数定义 }
b)注意:
把函数声明非模板函数:
friend ostream& operator<< (ostream& cout,const MGraph& G);
把函数声明为模板函数:
friend ostream& operator<< <>(ostream& cout,const MGraph<VexType,ArcType>& G); 或: friend ostream& operator<< <VexType,ArcType>(ostream& cout,const MGraph<VexType,ArcType>& G);
说明:
在函数声明中加入operator<< <>:是将operator<<函数定义为函数模板,将函数模板申明为类模板的友员时,是一对一绑定的
实际的声明函数:这里模板参数可以省略,但是尖括号不可以省略
使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
友元函数和类的成员函数的区别:成员函数有this指针,而友元函数没有this指针。
记忆:A是B的友元《=》A是B的朋友《=》借助B的对象,在A中可以直接 通过B。成员变量(可以是公有,也可以为私有变量) 的方式访问B
//测试一:普通函数友元函数 ////////////////////////////////////////////////////////////////////////// class IntegerNumber { ////////////////////////////////////////////////////////////////////////// public: void SetNumber(int a, int b, int c) { m_nPublicNumber = a; m_nProtectedNumber = b; m_nPrivateNumber= c; } ////////////////////////////////////////////////////////////////////////// public: void PrintPublicNumber() { cout<<"[PrintPublicMethod] Public Number is " << m_nPublicNumber << endl; } protected: void PrintProtectedNumber() { cout<<"[PrintProtectedMethod] Protected Number is " << m_nProtectedNumber << endl; } private: void PrintPrivateNumber() { cout<<"[PrintPrivateMethod] Private Number is " << m_nPrivateNumber << endl; } ////////////////////////////////////////////////////////////////////////// //由于友元函数没有this指针,所以一般要求用户传入友元函数所在类的一个对象 //结论一:声明友元函数,友元函数的访问权限不受 public | protected | private 影响 public: friend void PublicFriend(IntegerNumber& number) { cout << "--------------------------------------------------------\n"; //结论二:友元函数可以访问对象的所有成员 cout << "[PublicFriend] Public Number is " << number.m_nPublicNumber << endl; //友元函数可以访问公有成员 cout << "[PublicFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员 cout << "[PublicFriend] Private Number is " << number.m_nPrivateNumber << endl; //友元函数可以访问私有成员 ////结论三:友元函数可以访问对象的所有方法 number.PrintPublicNumber(); //友元函数可以访问公有方法 number.PrintProtectedNumber(); //友元函数可以访问保护方法 number.PrintPrivateNumber(); //友元函数可以访问私有方法 } protected: friend void ProtectedFriend(IntegerNumber& number) { cout << "--------------------------------------------------------\n"; cout << "[ProtectedFriend] Public Number is " << number.m_nPublicNumber << endl; //友元函数可以访问公有成员 cout << "[ProtectedFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员 cout << "[ProtectedFriend] Private Number is " << number.m_nPrivateNumber << endl; //友元函数可以访问私有成员 number.PrintPublicNumber(); //友元函数可以访问公有方法 number.PrintProtectedNumber(); //友元函数可以访问保护方法 number.PrintPrivateNumber(); //友元函数可以访问私有方法 } private: friend void PrivateFriend(IntegerNumber& number) { cout << "--------------------------------------------------------\n"; cout << "[PrivateFriend] Public Number is " << number.m_nPublicNumber << endl; //友元函数可以访问公有成员 cout << "[PrivateFriend] Protecdted Number is " << number.m_nProtectedNumber << endl; //友元函数可以访问保护成员 cout << "[PrivateFriend] Private Number is " << number.m_nPrivateNumber << endl; //友元函数可以访问私有成员 number.PrintPublicNumber(); //友元函数可以访问公有方法 number.PrintProtectedNumber(); //友元函数可以访问保护方法 number.PrintPrivateNumber(); //友元函数可以访问私有方法 } ////////////////////////////////////////////////////////////////////////// public: int m_nPublicNumber; protected: int m_nProtectedNumber; private: int m_nPrivateNumber; }; ////////////////////////////////////////////////////////////////////////// void FriendMethodTest() { IntegerNumber cNumber; cNumber.SetNumber(8, 9, 10); //友元函数只能采取以下直接调用的方式 ////////////////////////////////////////////////////////////////////////// PublicFriend(cNumber);//直接调用 ProtectedFriend(cNumber);//直接调用 PrivateFriend(cNumber);//直接调用 // C2039: 'PublicFriend' : is not a member of 'IntegerNumber' //cNumber.PublicFriend(cNumber); //友元函数无法采用一般成员函数的调用方式 //error C2039: 'ProtectedFriend' : is not a member of 'IntegerNumber' //cNumber.ProtectedFriend(cNumber); //友元函数无法采用一般成员函数的调用方式 //error C2039: 'PrivateFriend' : is not a member of 'IntegerNumber' //cNumber.PrivateFriend(cNumber); //友元函数无法采用一般成员函数的调用方式 } void NormalMethodTest() { IntegerNumber cNumber; cNumber.SetNumber(8, 9, 10); //正常情况下,对象只能访问公有成员,无法访问保护成员和私有成员。 ////////////////////////////////////////////////////////////////////////// cout << "Public Number is " << cNumber.m_nPublicNumber << endl; //一般对象可以访问公有成员 //error C2248: 'IntegerNumber::m_nProtectedNumber' : cannot access protected member declared in class 'IntegerNumber' //cout << "Protecdted Number is " << cNumber.m_nProtectedNumber << endl; //一般对象无法访问保护成员 //error C2248: 'IntegerNumber::m_nPrivateNumber' : cannot access private member declared in class 'IntegerNumber' //cout << "Private Number is " << cNumber.m_nPrivateNumber << endl; //一般对象无法访问私有成员 //正常情况下,对象只能访问公有方法,无法访问保护方法和私有方法。 ////////////////////////////////////////////////////////////////////////// cNumber.PrintPublicNumber(); //一般对象可以访问公有方法 //error C2248: 'IntegerNumber::PrintProtectedNumber' : cannot access protected member declared in class 'IntegerNumber' //cNumber.PrintProtectedNumber(); //一般对象无法访问保护方法 //error C2248: 'IntegerNumber::PrintPrivateNumber' : cannot access private member declared in class 'IntegerNumber' //cNumber.PrintPrivateNumber(); //一般对象无法访问私有方法 } void main() { NormalMethodTest(); FriendMethodTest(); }
//测试二:指定其他类的方法为自己的友元函数 class Girl; class Boy { public: Boy(int nId, int nAge) { m_nID = nId; m_nAge = nAge; } void Display(Girl& girl); private: int m_nID; int m_nAge; }; class Girl { public: Girl(int nId, int nAge) { m_nID = nId; m_nAge = nAge; } //声明类Boy的成员函数DispGirl()为类Girl的友元函数 friend void Boy::Display(Girl& girl); private: int m_nID; int m_nAge; }; void Boy::Display(Girl& girl) { //访问自己(Boy)的对象成员,直接访问自己的私有变量 cout << "Boy's id is:" << m_nID << ",age:" << m_nAge << endl; //借助友元,在Boy的成员函数disp中,借助Girl的对象,直接访问Girl的私有变量 //正常情况下,只允许在Girl的成员函数中访问Girl的私有变量 cout << "Girl's id is:" << girl.m_nID<< ",age:" << girl.m_nAge <<endl; } void FriendMethodByOtherClassTest() { Boy b(123, 18); Girl g(345, 20); b.Display(g); } void main() { FriendMethodByOtherClassTest(); }
//测试三:友元类,可以访问类的全部函数,可以理解成特殊的友元函数 class Wife; class Husband { private: int m_nMoney; public: Husband(int nMoney) { m_nMoney = nMoney; } void Display(Wife& wife); }; class Wife { private: int m_nMoney; friend Husband; //声明类Husband是类Wife的友元类 public: Wife(int nMoney) { m_nMoney = nMoney; } }; //函数Display()为类Husband的成员函数,也是类Wife的友元函数 void Husband::Display(Wife& wife) { //正常情况,Husband的成员函数disp中直接访问Husband的私有变量 cout << "Husband's money is:" << m_nMoney << endl; //借助友元类,在Husband的成员函数disp中,借助Wife的对象,直接访问Wife的私有变量 //正常情况下,只允许在Wife的成员函数中访问Wife的私有变量 cout << "Wife's money is:" << wife.m_nMoney <<endl; } void FrientClassTest() { Husband h(123); Wife w(456); h.Display(w); //h调用自己的成员函数,但是以w为参数,友元机制体现在函数Display中 } void main() { FrientClassTest(); }
//测试四:友元函数进行操作符重载 #include <iostream> #include <string> using namespace std; class rect { int x1, y1, x2, y2; //矩形座标 public: rect() { x1 = 0, y1 = 0, x2 = 0, y2 = 0; } rect(int m1, int n1, int m2, int n2) { x1 = m1, y1 = n1, x2 = m2, y2 = n2; } void print() { cout << " x1=" << x1; cout << " y1=" << y1; cout << " x2=" << x2; cout << " y2=" << y2; cout << endl; } //rect operator++(); //这是类的运算符的重载 friend rect operator++(rect &ob); //这是全局运算符的重载 }; rect operator++(rect &ob) { ob.x1++, ob.y1++; ob.x2++, ob.y2++; return ob; } int main ( ) { rect r(12, 20, 50, 40); r.print(); rect obj; obj = r++; obj.print(); return 0; }