C++中的友元小结

来源:互联网 发布:手机行业进销存软件 编辑:程序博客网 时间:2024/05/22 11:30

我们知道,在一个类总可以有公有的(public)成员和私有的(private)成员。在类外可以访问公用成员,只有本类中的函数可以访问本类的私有成员。

现在,我们学习一种新的情况——友元。

在C++中,这种关系以关键字friend声明。友元可以访问与其有好友关系的类中的私有成员。包括友元函数和友元类。

友元函数

如果在本类意外的其他地方定义了一个函数(这个函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数),在类体中用friend对该函数进行声明,此函数就称为本类的友元函数。一个类的友元函数可以访问这个类中的私有成员。


将普通函数声明为友元函数

========通过程序1.1来了解友元函数的性质和作用============

#include<iostream>using namespace std;class Time{public:Time(int,int,int);//声明构造函数 friend void display(Time &);//声明display函数为Time类的友元private:int hour;int minute;int second; };Time::Time(int h,int m,int s)//定义构造函数,完成初始化工作 {hour=h;minute=m;second=s;}void display(Time &t)//友元函数,形参t是Time类对象的引用 {cout<<t.hour<<"/"<<t.minute<<"/"<<t.second<<endl;}int main(){Time t1(10,13,56);display(t1);return 0; }    

运行结果:

分析:

display函数是一个在类外定义的非成员函数,它不属于任何一个类。如果在Time类的定义体中未声明display函数为friend函数,它是不能引用Time中的私有成员hour,minute和second的。

否则就会提示hour,minute和second是private函数,没有权限访问的错误。

由于我们在定义Time的时候,声明了display函数是其友元函数,Time所定义的所有的对象都会把dispaly函数作为自己的“朋友”,允许display函数引用其私有成员hour,minute和second.

但是要注意,我们在使用dispaly函数的时候,形参是对象的引用,实参是对象。

我们在友元函数中引用这些私有数据成员时,必须加上对象名,而不能写成:

cout<<hour<<"/"<<minute<<"/"<<second<<endl;
因为display函数不是Time类的成员函数,不能默认引用Time类的数据成员,必须指定要访问的对象。

友元成员函数

friend函数不仅可以是一般函数(非成员函数),而且可以是另一个类中的成员函数。

在举这个例子之前,我们需要先了解“类的提前引用声明

在C++中允许对类做“提前引用”的声明,即在正式声明一个类之前,先声明一个类名,表示此类将在稍后声明。

函数的提前引用声明,只包含类名,不包含类体。

class Date;//对Date类做提前声明

类的提前声明的使用范围是有限的,在对一个类作了提前引用声明后,可以用该类的名字去定义指向该类型对象的指针变量或对象的引用。

这是因为指针变量和引用本身的大小是固定的,与它所指定的类对象的大小无关。

然后,只有在正式声明一个类之后才能用它去定义类对象。因为在正式声明类之前就去定义对象的话,编译系统并不知道对象的结构,也就没有办法给对象分配空间,所以不能定义对象。

================示例代码1.2==============================

#include<iostream>using namespace std;class Date;//对Date类的提前引用声明class Time {public:Time(int ,int ,int);void display(Date &);private:int hour;int minute;int second;};class Date{public:Date(int,int,int);friend void Time::display(Date &);//声明Time类中的display函数为本类的友元函数private:int month;int day;int year; };Time::Time(int h,int m,int s)//定义类Time的构造函数{hour=h;minute=m;second=s;} /*display函数是Time类的成员函数;display函数是Date类的友元函数*/ void Time::display(Date &d)//display函数的作用是输出年月日和时分秒{cout<<d.year<<"/"<<d.month<<"/"<<d.day<<endl;//引用Date类对象中的私有成员cout<<hour<<":"<<minute<<":"<<second<<endl; } Date::Date(int y,int m,int d)//类Date的构造函数 {year=y;month=m;day=d;}int main(){Time t1(15,30,30);Date d1(2013,9,8);t1.display(d1);return 0;}

运行结果:

分析:

为了在Time类的定义中,能够定义形参是Date类对象引用的函数display。我们在代码的第三行,提前声明了类Date。

然后,在定义类Date的时候,我们在程序的第18行代码中,声明了Time的成员函数display函数为Date的友元成员函数,以达到能够访问Date中的私有数据成员的目的。

因为dispaly是Time中的成员函数,所以该函数可以访问Time类对象的私有数据成员;又因为Date类在声明的时候,将display函数声明为了其友成员函数,所以display函数也可以访问Date中的私有数据成员。

所以在程序的第倒数第3行才可以顺利的输出日期和时间。

友元类

不仅可以将一个函数声明为一个类的“朋友”,而且可以将一个类(例如类B)声明为另一个类(例如类A)的“朋友”。这是B类就是A类的友元类。友元类B中的所有函数都是A类的友元函数,可以访问A类中的所有成员。

在A类的定义体中用一下语句声明B类为其友元类:

friend class B;

声明友元类的一般形式:

friend class B;

例如,我们可以将程序1.2中的Time类声明为Date类的友元类,这样Time中的所有函数都可以访问Date类中的数据成员。

修改代码如下

===============示例代码2.1============================

#include<iostream>using namespace std;class Date;//对Date类的提前引用声明class Time {public:Time(int ,int ,int);void display(Date &);private:int hour;int minute;int second;};class Date{public:Date(int,int,int);friend class Time;//声明Time类为本类的友元类 private:int month;int day;int year; };Time::Time(int h,int m,int s)//定义类Time的构造函数{hour=h;minute=m;second=s;} /*display函数是Time类的成员函数;display函数是Date类的友元函数*/ void Time::display(Date &d)//display函数的作用是输出年月日和时分秒{cout<<d.year<<"/"<<d.month<<"/"<<d.day<<endl;//引用Date类对象中的私有成员cout<<hour<<":"<<minute<<":"<<second<<endl; } Date::Date(int y,int m,int d)//类Date的构造函数 {year=y;month=m;day=d;}int main(){Time t1(15,30,30);Date d1(2013,9,8);t1.display(d1);return 0;}

运行结果同示例代码1.2是一样的


说明:

关于友元有两点需要说明:

(1)友元的关系是单向的,而不是双向的。如果只声明了B类是A类的友元类,则B中的成员函数可以访问A中的私有数据成员;而A中的成员函数是不可以访问B中的数据成员的。

如果想要实现A和B互为友元类的话,需要即在A的声明体中声明B是其友元类,又要在B的声明体中声明A是其友元类。

(2)友元类的关系不能传递。如果B是A的友元类,C是B的友元类,不等于C是A的友元类。

在实际工作中,除非有必须,一般并不把整个类声明为友元类,而只是将确实有需要的成员函数声明为友元函数,这样更加安全一些。

原创粉丝点击