我们知道,在一个类总可以有公有的(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的友元类。

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

C++中的友元小结的更多相关文章

  1. MVC图片上传详解 IIS (安装SSL证书后) 实现 HTTP 自动跳转到 HTTPS C#中Enum用法小结 表达式目录树 “村长”教你测试用例 引用provinces.js的三级联动

    MVC图片上传详解   MVC图片上传--控制器方法 新建一个控制器命名为File,定义一个Img方法 [HttpPost]public ActionResult Img(HttpPostedFile ...

  2. C++中的友元函数和友元类

    C++中的友元函数主要应用于以下场景: 友元函数 第一种场景 代码中有一个全局函数,该函数想要去访问某个类的成员变量(该类的成员变量是private的,且该类并未提供任何获取获取私有成员变量的publ ...

  3. 180531-Spring中JavaConfig知识小结

    原文链接:Spring中JavaConfig知识小结/ Sring中JavaConfig使用姿势 去掉xml的配置方式,改成用Java来配置,最常见的就是将xml中的 bean定义, scanner包 ...

  4. [转] SpringBoot RESTful 应用中的异常处理小结

    [From] https://segmentfault.com/a/1190000006749441 SpringBoot RESTful 应用中的异常处理小结 永顺 2016年08月29日发布 赞  ...

  5. hiredis中异步的实现小结

    hiredis中异步的实现小结 原文: http://blog.csdn.net/l1902090/article/details/3858... 时间: 2014-08-15 前言 一般情况下我们使 ...

  6. C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路

    C#不用union,而是有更好的方式实现   用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...

  7. C#中实现C++中的友元类

    最近做一个小程序,一个类A(负责显示处理)需要大量调用类B(负责数据处理)的函数,我最先想到的C++中的友元概念,因为类B中的这些函数并不希望public,它只是允许类A调用监测. 网上搜索了一下,没 ...

  8. 04 c++中的友元

    c++中的类具有封装性,类中的私有数据只有该类的成员函数可以访问,程序中访问类中的私有成员,必须通过对象来调用成员函数,但是频繁的调用会使运行效率降低. 为了解决上述问题,c++中加入友元机制,友元可 ...

  9. 关于C++中的友元函数的总结

    1.友元函数的简单介绍 1.1为什么要使用友元函数 在实现类之间数据共享时,减少系统开销,提高效率.如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数.具 ...

随机推荐

  1. Spring Cloud之Feigin客户端重构思想

    应该重构接口信息(重点) toov5-parent  存放共同依赖信息 toov5-api       api的只有接口没有实现 toov5-api-member toov5-api-order to ...

  2. ThinkPHP 小技巧

    中文截取函数 函数解释: msubstr($str, $start=0, $length, $charset=”utf-8″, $suffix=true) $str:要截取的字符串 $start=0: ...

  3. castle windsor学习----- Referencing types in XML 在xm文件中引用类型

    当从xml引用installer的语法如下 <install type="Acme.Crm.Infrastructure.ServicesInstaller, Acme.Crm.Inf ...

  4. plsql点击不再提示后需重新提示

    工具--首选项---用户界面---选项---DSA对话框---内容如下 ;显示含有“不再显示这个信息”的对话框;你可以删除用于你要启用的信息的行 CharSetMismatch@RIM40=1Char ...

  5. HTML5 学习记录——2

    20150826 1.声明文档类型 <!DOCTYPE>  声明HTML是用什么版本写的. 常用声明; 2.HYML头部元素   <head> <title> 定义 ...

  6. Python with MYSQL - sytax problem

    Con= MySQLdb.connect(host=',db='test') cur=Con.cursor() cur.execute('insert into staff_daily(Date,Na ...

  7. 判断浏览器是否支持css3属性或单位

    1.用CSS.supports()方法 mark-zhq[3] //判断是否支持flex布局 var supportsFlex = CSS.supports("display", ...

  8. 基于DirectShow和FFmpeg的USB摄像头监控软件-转

    第一个版本 ### 软件版本及实现功能 0.0.1 1. USB摄像头枚举和设备信息获取2. 实时视频观看3. 24小时不间断录像,录像文件支持暴风影音播放 ### 软件说明: 软件基于 Direct ...

  9. Silk codec的一些资料

    Skype表示它最近将开始向第三方开发人员和硬件制造商提供免版税认证(RF)的Silk宽带音频编码器. Silk下载地址如下 http://developer.skype.com/silk/SILK_ ...

  10. luogu1833 樱花

    背包问题小合集 01背包 完全背包 多重背包混着来 对于01背包:把它想象成最大物品数为1的多重背包 对于完全背包:把它想象成最大物品数为m/w[i]的多重背包 对于多重背包:把它想象成...等等这本 ...