参考链接
[url]http://blog.csdn.net/insistgogo/article/details/6608672[/url]
[url]http://www.cnblogs.com/fzhe/archive/2013/01/05/2846808.html[/url]
[b]1、为什么要引入友元函数:在实现类之间数据共享时,减少系统开销,提高效率[/b]
具体来说:为了使其他类的成员函数直接访问该类的私有变量
即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数
优点:能够提高效率,表达简单、清晰
缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。
[b]2、什么时候使用友元函数:[/b]
1)运算符重载的某些场合需要使用友元。
2)两个类要共享数据的时候
[b]3、怎么使用友元函数[/b]
[color=darkred]友元函数的参数[/color]
因为友元函数没有this指针,则参数要有三种情况:
1、 要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)
2、 要访问static成员或全局变量时,则不需要对象做参数
3、 如果做参数的对象是全局对象,则不需要对象做参数
[color=darkred]友元函数的位置[/color]
因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。
[color=darkred]友元函数的调用[/color]
可以直接调用友元函数,不需要通过对象或指针
[color=darkred]友元函数的分类[/color]
根据这个函数的来源不同,可以分为三种方法:
[size=medium]1、普通函数友元函数:
a) 目的:使普通函数能够访问类的友元
b) 语法:声明位置:公有私有均可,常写为公有
声明: friend + 普通函数声明
实现位置:可以在类外或类中
实现代码:与普通函数相同(不加不用friend和类::)
调用:类似普通函数,直接调用[/size]
[size=medium]2、类Y的所有成员函数都为类X友元函数—友元类
a)目的:使用单个声明使Y类的所有函数成为类X的友元
它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能
具体来说:
前提:A是B的友元(=》A中成员函数可以访问B中有所有成员,包括私有成员和公有成员--老忘)
则:在A中,借助类B,可以直接使用~B . 私有变量~的形式访问私有变量
b)语法:声明位置:公有私有均可,常写为私有(把类看成一个变量)
声明: friend + 类名---不是对象啊
调用:[/size]
[size=medium]3、类Y的一个成员函数为类X的友元函数
a)目的:使类Y的一个成员函数成为类X的友元
具体而言:而在类Y的这个成员函数中,借助参数X,可以直接以X。私有变量的形式访问私有变量
b)语法:声明位置:声明在公有中 (本身为函数)
声明:friend + 成员函数的声明
调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制[/size]
4、在模板类中使用友元operator<<(对<<运算符的重载)
a)使用方法:
在模板类中声明:
friend ostream& operator<< <>(ostream& cout,const MGraph& G);
在模板类中定义:
template
ostream& operator<<(ostream& cout,const MGraph& G)
{
//函数定义
}
b)注意:
把函数声明非模板函数:
friend ostream& operator<< (ostream& cout,const MGraph& G);
把函数声明为模板函数:
friend ostream& operator<< <>(ostream& cout,const MGraph& G);
或:
friend ostream& operator<< (ostream& cout,const MGraph& G);
说明:
在函数声明中加入operator<< <>:是将operator<<函数定义为函数模板,将函数模板申明为类模板的友员时,是一对一绑定的
实际的声明函数:这里模板参数可以省略,但是尖括号不可以省略
[color=red][size=medium][b]使用友元类时注意:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明
友元函数和类的成员函数的区别:成员函数有this指针,而友元函数没有this指针。
记忆:A是B的友元《=》A是B的朋友《=》借助B的对象,在A中可以直接 通过B。成员变量(可以是公有,也可以为私有变量) 的方式访问B
[/b][/size][/color]
//测试一:普通函数友元函数
//
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();
}
[img]http://chuantu.biz/t5/10/1466043742x3738746553.jpg[/img]
//测试二:指定其他类的方法为自己的友元函数
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 <}
void FriendMethodByOtherClassTest()
{
Boy b(123, 18);
Girl g(345, 20);
b.Display(g);
}
void main()
{
FriendMethodByOtherClassTest();
}
[img]http://chuantu.biz/t5/10/1466045254x3738746553.jpg[/img]
//测试三:友元类,可以访问类的全部函数,可以理解成特殊的友元函数
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 <}
void FrientClassTest()
{
Husband h(123);
Wife w(456);
h.Display(w); //h调用自己的成员函数,但是以w为参数,友元机制体现在函数Display中
}
void main()
{
FrientClassTest();
}
[img]http://chuantu.biz/t5/10/1466046396x3738746553.jpg[/img]
//测试四:友元函数进行操作符重载
#include
#include
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;
}