C++_友元
友元
在一个类中可以有公用的(public)成员和私有的(private)成员。在类外可以访问公用成员,只有本类中的函数可以访问本类的私有成员。现在,我们来补充介绍一个例外——友元(friend)。
友元可以访问与其有好友关系的类中的私有成员。
友元包括友元函数和友元类。
友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数,还可以是整个的类。
1. 友元函数
友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有、保护和公有成员。
友元函数的声明:
- 位置:当前类体中.
- 格式: 函数名前加friend
友元函数的定义:
- 类体外:同一般函数(函数名前不能加 类名::)
- 类体内:函数名前加friend
友元函数 没有this指针,它是通过 入口参数(该类对象) 来访问对象的成员的。
例. 将普通函数声明为友元函数
#include <iostream>
using namespace std;
class Time{
public:
Time(int,int,int);
friend void display(Time &); //声明display函数为Time类的友元函数
private: //以下数据是私有数据成员
int hour;
int minute;
int sec;
};
Time∷Time(int h,int m,int s) //构造函数,给hour,minute,sec赋初值
{
hour=h;
minute=m;
sec=s;
}
void display(Time& t)
{
cout<<t.hour<<″:″<<t.minute<<″:″<<t.sec<<endl;
}
int main( )
{
Time t1(10,13,56);
display(t1);
return 0;
}
程序输出结果如下:
10:13:56
例3.22 友元函数的使用
#include<iostream.h>
#include<string.h>
class girl {
public:
girl(char *n,int d)
{
name=new char[strlen(n)+1];
strcpy(name,n);
age=d;
}
friend void disp(girl &); //声明友元函数
~girl(){ delete []name; }
private:
char *name;
int age;
};
void disp(girl &x) //定义友元函数
{
cout<<"Girl\′s name is "<<x.name<<",age:"<<x.age<<"\n";
}
void main()
{
girl e("Chen Xingwei",18);
disp(e); // 调用友元函数
}
说明
- (1) 友元函数虽然可以访问该类的私有成员,但它毕竟不是成员函数,因此,在类的外部定义友元函数时,不能在函数名前加上“类名::”。
- (2) 友元函数一般带有一个该类的入口参数。因为友元函数不是类的成员函数,它没有this指针,所以它不能直接引用对象成员的名字,也不能通过this指针引用对象的成员,它必须通过作为入口参数传递进来的对象名或对象指针来引用该对象的成员。
引入友元机制的原因
- (1) 友元机制是对类的封装机制的补充,利用此机制,一个类可以赋予某些函数访问它的私有成员的特权。
- (2) 友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。
- 友元函数可以是多个类的
#include<iostream.h>
#include<string.h>
class boy; //向前引用
class girl{
public:
void init(char N[],int A);
friend void prdata(const girl plg ,const boy plb);
private:
char name[25];
int age;
};
void girl∷init(char N[],int A)
{
strcpy(name, N);
age=A;
}
class boy {
public:
void init(char N[],int A);
friend void prdata(const girl plg,const boy plb);
private:
char name[25];
int age;
};
void boy∷init(char N[],int A)
{
strcpy(name,N);
age=A;
}
void prdata(const girl plg,const boy plb)
{
cout<<"name: "<<plg.name<<"\n";
cout<<"age: "<<plg.age<<"\n";
cout<<"name: "<<plb.name<<"\n";
cout<<"age: "<<plb.age<<"\n";
}
main()
{
girl G1,G2,G3;
boy B1,B2,B3;
G1.init("Zhang Hao",12);
G2.init("Li Ying",13);
G3.init("Wan Hong",12);
B1.init("Chen Lin",11);
B2.init("Wang Hua",13);
B3.init("Bai Xiu",12);
prdata(G1,B1); //调用友元函数prdata()
prdata(G2,B2); //调用友元函数prdata()
prdata(G3,B3); //调用友元函数prdata()
return 0;
}
- 友元成员函数不仅可以是一般函数(非成员函数),而且可以是另一个类中的成员函数
例:友元成员函数的简单应用。
#include <iostream>
using namespace std;
class Date; //对 Date类的提前引用声明
class Time{ //定义 Time类
public:
Time(int,int,int);
void display(Date &); //display是成员函数,形参是Date类对象的引用
private:
int hour;
int minute;
int sec;
};
class Date{ //声明 Date类
public:
Date(int,int,int);
friend void Time∷display(Date &);
private:
int month;
int day;
int year;
};
Time∷Time(int h,int m,int s) //类Time的构造函数
{
hour=h;
minute=m;
sec=s;
}
void Time∷display(Date &d)
{
cout<<d.month<<″/″<<d.day<<″/″<<d.year<<endl;
cout<<hour<<″:″<<minute<<″:″<<sec<<endl;
}
Date∷Date(int m,in d,int y) //类Date的构造函数
{
month=m;
day=d;
year=y;
}
int main( )
{
Time t1(10,13,56); //定义Time类对象t1
Date d1(12,25,2004); //定义Date类对象d1
t1.display(d1); //调用t1中的display函数,实参是Date类对象d1
return 0;
}
2. 友元成员
一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的所有成员,还可以访问friend声明语句所在类对象中的所有成员。
这样能使两个类相互合作、协调工作,完成某一任务。
一个类的成员函数作为另一个类的友元函数时,必须先定义这个类
例3.24 一个类的成员函数作为另一个类的友元。
#include<iostream.h>
#include<string.h>
class girl;
class boy {
public:
boy(char *n,int d)
{
name=new char[strlen(n)+1];
strcpy(name,n);
age=d;
}
void disp(girl &); // 声明disp()为类boy的成员函数
~boy(){ delete name; }
private:
char *name;
int age;
};
class girl {
public:
girl(char *n,int d)
{
name=new char[strlen(n)+1];
strcpy(name,n);
age=d;
}
friend void boy::disp(girl &);
~girl(){ delete name; }
private:
char *name;
int age;
};
void boy::disp(girl &x)
{
cout<<"Boy\′s name is "<<name<<",age:"<<age<<"\n";
cout<<"Girl\′s name is "<<x.name<<",age:"<<x.age<<"\n";
}
void main()
{
boy b("Chen Hao",25);
girl e("Zhang Wei ",18);
b.disp(e);
}
程序运行结果如下:
Boy′s name is Chen Hao ,age: 25
Girl′s name is: Zhang Wei ,age: 18
3. 友元类
不仅可以将一个函数声明为一个类的“朋友”,而且可以将一个类(例如B类)声明为另一个类(例如A类)的“朋友”。这时B类就是A类的友元类。友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。
class Y {
//…
};
class X {
//…
friend Y; // 声明类Y为类X的友元类
//…
};
类Y的所有成员函数都是类X的友元函数
在实际工作中,除非确有必要,一般并不把整个类声明为友元类,而只将确实有需要的成员函数声明为友元函数,这样更安全一些。
关于友元利弊的分析:
面向对象程序设计的一个基本原则是封装性和信息隐蔽,而友元却可以访问其他类中的私有成员,不能不说这是对封装原则的一个小的破坏。但是它能有助于数据共享,能提高程序的效率,在使用友元时,要注意到它的副作用,不要过多地使用友元,只有在使用它能使程序精炼,并能大大提高程序的效率时才用友元。
【例3.25】 一个类作为另一个类的友元
#include<iostream.h>
#include<string.h>
class girl;
class boy{
public:
boy(char *n,int d)
{
name=new char[strlen(n)+1];
strcpy(name,n);
age=d;
}
void disp(girl&);
~boy()
{ delete name; }
private:
char *name;
int age;
};
class girl{
public:
girl(char *n,int d)
{
name=new char[strlen(n)+1];
strcpy(name,n);
age=d;
}
~girl()
{ delete name; }
private:
char *name;
int age;
friend boy;
};
void boy∷disp(girl &x)
{
cout<<"Boy\'s name is "<<name <<",age:"<<age<<"\n";
cout<<"Girl\'s name is "<<x.name <<",age:"<<x.age<<"\n";
}
void main()
{
boy b("Chen Hao",25);
girl e("Zhang Wei ",18);
b.disp(e);
}
注意:
- 友元关系是单向的,不具有交换性
即若类X是类Y的友元,但类Y不一定是类X的友元。
- 友元关系不具有传递性
即若类X是类Y的友元,类Y是类Z的友元,但类X不一定是类Z的友元。