C++中的友元小结
我们知道,在一个类总可以有公有的(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++中的友元小结的更多相关文章
- MVC图片上传详解 IIS (安装SSL证书后) 实现 HTTP 自动跳转到 HTTPS C#中Enum用法小结 表达式目录树 “村长”教你测试用例 引用provinces.js的三级联动
MVC图片上传详解 MVC图片上传--控制器方法 新建一个控制器命名为File,定义一个Img方法 [HttpPost]public ActionResult Img(HttpPostedFile ...
- C++中的友元函数和友元类
C++中的友元函数主要应用于以下场景: 友元函数 第一种场景 代码中有一个全局函数,该函数想要去访问某个类的成员变量(该类的成员变量是private的,且该类并未提供任何获取获取私有成员变量的publ ...
- 180531-Spring中JavaConfig知识小结
原文链接:Spring中JavaConfig知识小结/ Sring中JavaConfig使用姿势 去掉xml的配置方式,改成用Java来配置,最常见的就是将xml中的 bean定义, scanner包 ...
- [转] SpringBoot RESTful 应用中的异常处理小结
[From] https://segmentfault.com/a/1190000006749441 SpringBoot RESTful 应用中的异常处理小结 永顺 2016年08月29日发布 赞 ...
- hiredis中异步的实现小结
hiredis中异步的实现小结 原文: http://blog.csdn.net/l1902090/article/details/3858... 时间: 2014-08-15 前言 一般情况下我们使 ...
- C#不用union,而是有更好的方式实现 .net自定义错误页面实现 .net自定义错误页面实现升级篇 .net捕捉全局未处理异常的3种方式 一款很不错的FLASH时种插件 关于c#中委托使用小结 WEB网站常见受攻击方式及解决办法 判断URL是否存在 提升高并发量服务器性能解决思路
C#不用union,而是有更好的方式实现 用过C/C++的人都知道有个union,特别好用,似乎char数组到short,int,float等的转换无所不能,也确实是能,并且用起来十分方便.那C# ...
- C#中实现C++中的友元类
最近做一个小程序,一个类A(负责显示处理)需要大量调用类B(负责数据处理)的函数,我最先想到的C++中的友元概念,因为类B中的这些函数并不希望public,它只是允许类A调用监测. 网上搜索了一下,没 ...
- 04 c++中的友元
c++中的类具有封装性,类中的私有数据只有该类的成员函数可以访问,程序中访问类中的私有成员,必须通过对象来调用成员函数,但是频繁的调用会使运行效率降低. 为了解决上述问题,c++中加入友元机制,友元可 ...
- 关于C++中的友元函数的总结
1.友元函数的简单介绍 1.1为什么要使用友元函数 在实现类之间数据共享时,减少系统开销,提高效率.如果类A中的函数要访问类B中的成员(例如:智能指针类的实现),那么类A中该函数要是类B的友元函数.具 ...
随机推荐
- oc中的blocks的功能,一种比代理简洁的方式
blocks方式: 谁要东西谁就要写blocks,通过blocks(返回值)获取想要的,提供东西的人要通过实现函数指针把东西给想要的人.当然也可以传值,传值需要通过形参. block的功能: bloc ...
- ubuntu14.04 spring cloud config server + gradle搭建
Server端:在eclipse上,创建Java Project项目.自带的src包删掉手动建文件夹.基础的目录文件都创建上 |--ZSpringCloud|--build.gradle|----sr ...
- 第二篇 javascript一维数组和二维数组及方法
一.数组 什么是数组 程序=数据+算法 数组就是一种很常见的保存批量数据的数据结构 一.定义数组 var arr1=[]; //定义了一个不包含元素的数组 ,,]; //定义了一个包含三个元素的数组 ...
- 百度编辑器 Ueditor 如何增加字体 ?
在百度编辑器 Ueditor 如何增加字体 ? 要修改两个文件: 第一个文件:editor-config.js: ,'fontfamily':[ { label:'',name ...
- intel dpdk api interrupt module 中断模块介绍
声明:此文档只做学习交流使用,请勿用作其他商业用途 author:朝阳_tonyE-mail : linzhaolover@gmail.comCreate Date: 2013-7-12 11:46: ...
- BZOJ 1096 [ZJOI2007]仓库建设:斜率优化dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1096 题意: 有n个工厂,从左往右排成一排,分别编号1到n. 每个工厂里有p[i]件产品, ...
- css3 多列布局使用
css3的出现,解决了不少前端的问题,比如动画,圆角等: 这里总结一下css3 的多列布局: w3c上给出了很多属性: 我们一般用到column-count.column-gap.column-wid ...
- 单机版 JedisUtil({基本操作封装工具类})【二】
<!--集成的RedisJAR--> <!--引入jedis需的jar包--> <dependency> <groupId>redis.clients& ...
- Git_学习_00_资源帖
1.廖雪峰: (1)Git教程 2.阮一峰: (1)Git分支管理策略 (2)Git远程操作详解 (3)Git 使用规范流程 (4)Github 的清点对象算法 (5)常用 Git 命令清单 (6)G ...
- 原生JS实现淡入淡出效果(fadeIn/fadeOut/fadeTo)
淡入淡出效果,在日常项目中经常用到,可惜原生JS没有类似的方法,而有时小的页面并不值得引入一个jQuery库,所以就自己写了一个,已封装, 有用得着的朋友, 可以直接使用. 代码中另附有一个设置元素透 ...