1.何为友元?

类可以允许其他类或者函数访问它的非公有成员(通过类的对象),方式是令其他类或者函数成为它的友元(需要用到friend关键字)。

2.友元分类

3.非成员函数作为友元函数

示例代码结构如下:

// Student.hpp#ifndef STUDENT_HPP
#define STUDENT_HPPclass Student {
public:friend void ModifyAge( Student &stu, int value );Student():age(18){}~Student(){}int GetAge(){return age;}void SetAge( int tmp ){age = tmp;}
private:int age;
};
void ModifyAge( Student &stu, int value );
#endif /* STUDENT_HPP */
// Student.cpp#include "Student.hpp"void ModifyAge( Student &stu, int value ){stu.age = value;
}
// main.cpp#include <iostream>
#include "Student.hpp"using namespace std;int main( void ){Student a;cout << a.GetAge() << endl;ModifyAge( a, 25 );cout << a.GetAge() << endl;return 0;
}

友元声明只能出现在类定义的内部,但是在类内出现的具体位置没有限制。

并且友元不是类的成员,不受它所在区域,访问控制级别的约束(不受public,private的约束)。

特别注意:友元声明仅仅是指定了访问权限,也就是告诉Student这个类,ModifyAge可以访问age这个私有数据成员。类定义中 ModifyAge函数的友元声明,并不是普通意义上的函数声明。因此,在类定义的外部,我们单独对ModifyAge函数进行了声明(注意这里没有用friend关键字)。

如果我们没有在类的外部对ModifyAge函数进行声明,main.cpp的内容如下所示:

// main.cpp#include <iostream>class Student {
friend void ModifyAge( Student &stu, int value );public:Student():age(18){}~Student(){}int GetAge(){return age;}void SetAge( int tmp ){age = tmp;}private:int age;
};using namespace std;int main( void ){Student a;cout << a.GetAge() << endl;ModifyAge( a, 25 );         // 这里在编译时会报错,在当前文件中,找不到ModifyAge函数的声明cout << a.GetAge() << endl;return 0;
}

许多编译器并未强制要求友元函数必须在使用之前在类的外部声明。上述错误,不一定在你的编译环境中会复现。但是,出于代码的可移植性,我们最好还是在类定义的外部,单独对友元函数进行声明。

4.类是友元

示例代码结构如下:

// Student.hpp#ifndef STUDENT_HPP
#define STUDENT_HPPclass Student {
friend class Teacher;public:Student():age(18){}~Student(){}int GetAge(){return age;}void SetAge( int tmp ){age = tmp;}
private:int age;
};
#endif /* STUDENT_HPP */
// Teacher.hpp#ifndef TEACHER_HPP
#define TEACHER_HPP#include "Student.hpp"class Teacher {
public:Teacher() = default;virtual ~Teacher();void SetStudentAge( Student &stu, int value );
private:};#endif /* TEACHER_HPP */
// Teacher.cpp#include "Teacher.hpp"Teacher::~Teacher() {
}void Teacher::SetStudentAge( Student &stu, int value ){stu.age = value;
}
// main.cpp#include <iostream>
#include "Student.hpp"
#include "Teacher.hpp"using namespace std;int main( void ){Student a;cout << a.GetAge() << endl;Teacher t1;t1.SetStudentAge(a,30);cout << a.GetAge() << endl;return 0;
}

5.类的成员函数是友元

示例代码结构如下:

// Student.hpp#ifndef STUDENT_HPP
#define STUDENT_HPP// 这里包含Teacher1的头文件,是因为友元声明中用到了Teacher1::
#include "Teacher1.hpp"class Student {
friend void Teacher1::SetStuAge( Student &stu, int value );public:Student():age(18){}~Student(){}int GetAge(){return age;}void SetAge( int tmp ){age = tmp;}private:int age;
};
#endif /* STUDENT_HPP */
// Teacher1.hpp#ifndef TEACHER1_HPP
#define TEACHER1_HPP// 注意:这里没有包含Student的头文件
// 这里用的是不完全类型(C语言中结构的不完整声明)
class Student;class Teacher1 {
public:Teacher1();void SetStuAge( Student &stu, int value );virtual ~Teacher1();
private:};#endif /* TEACHER1_HPP */
// Teacher1.cpp#include "Teacher1.hpp"
#include "Student.hpp"    // 这里包含了Student头文件
Teacher1::Teacher1() {
}Teacher1::~Teacher1() {
}void Teacher1::SetStuAge( Student &stu, int value ){stu.age = value;
}
// main.cpp#include <iostream>
#include "Student.hpp"
#include "Teacher1.hpp"using namespace std;int main( void ){Student a;cout << a.GetAge() << endl;Teacher1 t2;t2.SetStuAge(a,35);cout << a.GetAge() << endl;return 0;
}

到这里三种友元类型的示例都展示完成了。

最不好理解的就是成员函数作为友元的情况,需要组织好类的结构,不然编译时,很容易报错。

下面对第三种情况做一个总结。

类B有一个成员函数B::func(),是类A的友元,那么三者需要按照下面的顺序进行组织:

  • 首先定义类B,声明func函数,但是不能定义它。同时需要在定义类B之前,声明类A(不完整声明)。
  • 定义类A,包括对B::func函数的友元声明(#include "B.hpp")。
  • 最后定义B::func,此时它才可以使用类A的私有成员。

6.注意事项

  • 友元是为了兼顾 C 语言的高效而诞生的(通过对象直接访问私有数据成员,不需要再使用成员函数去访问私有数据成员,减少了函数调用的开销)
  • 友元直接破坏了面向对象的封装性
  • 友元关系不具备传递性

C++友元知识点详解相关推荐

  1. Zookeeper知识点详解

    Zookeeper知识点详解 目录 ZooKeeper 集群原理 ZooKeeper 分布式锁 ZooKeeper 分布式事务 ZooKeeper 选举原理 Paxos 协议 ZAB 协议 ZooKe ...

  2. python 消息队列 get是从队首还是队尾取东西_python分布式爬虫中消息队列知识点详解...

    当排队等待人数过多的时候,我们需要设置一个等待区防止秩序混乱,同时再有新来的想要排队也可以呆在这个地方.那么在python分布式爬虫中,消息队列就相当于这样的一个区域,爬虫要进入这个区域找寻自己想要的 ...

  3. mysql text类型 使用方法_MySQL使用TEXT/BLOB类型的知识点详解

    一.TEXT和BLOB的区别 TEXT和BLOB家族之间仅有的不同是BLOB类型存储的是二进制数据,没有排序规则或字符集,而TEXT类型有字符集或排序规则.说白了如果要储存中文则选择TEXT. 二.默 ...

  4. python源程序文件的扩展名_python程序文件扩展名知识点详解

    python程序文件的扩展名称是什么 python程序的扩展名有.py..pyc..pyo和.pyd..py是源文件,.pyc是源文件编译后的文件,.pyo是源文件优化编译后的文件,.pyd是其他语言 ...

  5. java中流_Java中流的有关知识点详解

    Java中流的有关知识点详解 发布时间:2020-09-17 03:50:59 来源:脚本之家 阅读:103 作者:mumu1998 什么是流? 流:程序和设备之间连接起来的一根用于数据传输的管道,流 ...

  6. design短语的用法总结_最新高中英语知识点详解之design的用法及常见短语

    英语的应用越来越广泛了,我们必须好好来学习英语知识.对此小学频道编辑为大家整理了最新高中英语知识点详解之design的用法及常见短语.详情如下: design的用法 n.设计;图案;构思 vt.设计; ...

  7. 学习电气自动化PLC编程最基础的十大知识点详解

    这篇文章其实是学习PLC自动化过程中必须要理解的基础问题,不管是西门子PLC还是三菱PLC,抑或欧姆龙PLC,以及国产品牌的PLC,这些问题都必须理解透,才能更好的开始自动化编程.不然指令学完了梯形图 ...

  8. Pandas知识点-详解行列级批处理函数apply

    Pandas知识点-详解行列级批处理函数apply 在Pandas中,DataFrame和Series等对象需要执行批量处理操作时,可以借用apply()函数来实现. apply()的核心功能是实现& ...

  9. python 消息队列 flask_python分布式爬虫中消息队列知识点详解

    当排队等待人数过多的时候,我们需要设置一个等待区防止秩序混乱,同时再有新来的想要排队也可以呆在这个地方.那么在python分布式爬虫中,消息队列就相当于这样的一个区域,爬虫要进入这个区域找寻自己想要的 ...

最新文章

  1. ubuntu下matplotlib 升级
  2. 并发基础(一):Executor
  3. 第二篇T语言实例开发(版本5.3),福彩3D摇号器
  4. 【C++】21.函数传参 传指针和传引用的区别
  5. 一段把mp4中的音频提取并保存在原目录的python脚本
  6. java面试题3(java基础)
  7. 安装eclipse时遇到的问题
  8. global与nonlocal关键字
  9. 中山大学曾兆阳_2010—2011学年度中山大学信科院优秀学生奖学金评选结果名单...
  10. java 系统自动检测_如何在Java中检测OS(操作系统)名称?
  11. Spring MVC遭遇checkbox的问题解决方案
  12. TensorFlow 2.4 发布
  13. yolov5数据集标注txt2xml和xml2txt
  14. systemd (简体中文)
  15. 超简单的windows发包工具—小兵以太网测试仪
  16. asp.net core mvc 项目搭建 二、hplus UI【干货教程】
  17. 数字图像处理 冈萨雷斯(第四版)图像分辨率及大小,灰度级变化的影响,以及邻接、连通、区域和边界笔记
  18. 美服fgo显示服务器异常,FGO日服美服错误代码合集_FGO日服美服错误代码汇总_牛游戏网...
  19. 区块链技术与应用(北大公开课,肖臻)- 课程总结
  20. 基于Android studio+SSH的单词记忆(背单词)APP设计

热门文章

  1. SQL查询结果单位换算后保留两位小数
  2. 数学建模与MATLAB计算之006.MATLAB中的条件语句
  3. matlab条件语句怎么写,matlab if 条件语句 用法以及实例是什么
  4. python 回文数判断
  5. 机器翻译及其相关技术介绍
  6. [Python] 信息论:计算机自信息,信息熵,对比中文和英文信息熵。
  7. 致北漂Linux伙伴们的一封信
  8. java计算机毕业设计高校人事管理系统源码+mysql数据库+系统+lw文档+部署
  9. Docker容器的部署安装与管理
  10. MySql二进制文件解析系统