IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++ 学习总结】- 03 - 类的认识:友元类和友元函数 -> 正文阅读

[C++知识库]【C++ 学习总结】- 03 - 类的认识:友元类和友元函数


一、友元的概念

1. 基本概念

??「 友元(friend)」 是一个用以帮助其他类中的成员函数以及全局范围的函数访问当前类的 privateprotected 成员的机制。使用友元机制的可以是类,也可以是不属于本类的函数,但无一例外都需要先在要建立 “friend” 关系的目标类里使用 <friend> 关键字先进行友元声明。声明为友元函数后,函数可以访问本不可以访问的类的 privateprotected 成员,而友元类中的每个成员函数都可以访问建立了友元关系的目标类的所有成员。

??对于 <friend> 这个词我们可以这么理解:对外人我们会保持警惕、潜意识里自我保护,但是和亲密的朋友就会敞开心扉、分享秘密,而对于类来说友元关系就是其分享本为私密的成员变量给声明为友元的目标。


《挑战30天C/C++》 中这样说道:
??友元能够使得普通函数直接访问类的保护数据,避免了类成员函数的频繁调用,可以节约处理器开销,提高程序的效率。但所矛盾的是,即使是最大限度的保护,同样也破坏了类的封装特性,这即是友元的缺点。在现在cpu速度越来越快的今天我们并不推荐使用它,但它作为 C++ 的一个必要的知识点,一个完整的组成部分,我们还是需要讨论一下的。


2. 友元的特性

  • 友元在不破坏类的整体封装性的前提下,向外部函数特殊地提供了其内部访问权,以实现某些特殊功能。

  • 友元定义在外部,但是需要在类的内部进行友元声明,从而确定要建立友元关系的目标类。

  • 友元是单向的,类A在类B中声明了友元 friend class A;,那么A可以访问B,但是B不能访问A

  • 友元关系不能被传递。附庸的附庸不是我的附庸,友元的友元不是我的友元。

  • 友元关系不能被继承,因为友元并不是类的成员。

  • 友元不是类的成员,不受类的访问权限关键字 publicprotectedprivate 的修饰。

  • 友元不是类的成员,没有 this 指针,所以不能访问类的非 static 成员。因此,需要在其参数中手动地指明目标对象。

  • 友元不是类的成员,因此无需通过对象而可以直接调用。


二、友元的使用

1. 友元的声明

??通过在目标类中使用 <friend> 关键字进行声明来使函数或类成为目标类的友元函数、友元类,声明方法为在原声明语句前添加一个关键字 <friend>,其语法格式如下:

	// 声明友元关系
	class classA {
		access specifier:
			// member variables
			// member functions
			friend class classB;		// 声明友元类
			friend varType funcName (parameters);	// 声明友元函数
	}

??经过声明的友元函数即可访问类中的所有成员。需要注意的是,如果访问的不是 static 成员,就需要在参数中指明目标对象。我们知道,成员函数实际上有一个隐式的 this 指针指向当前对象,用于访问对象的成员,而友元函数并不是本类的成员函数,也就没有 this 指针,无从访问对象的成员,所以我们就需要手动地为其指明要访问的对象。
??经过声明的友元类的所有成员函数都可以访问目标类中的所有成员,这种方法好在可以一次性地对所有成员函数完成友元声明而不必再一次次地进行繁杂重复的声明工作,坏处是增加了类的封装性被破坏的风险。因此,一般不建议将整个类声明为友元。


2. 示例1:非成员函数声明为友元函数

================================ 定义示例 ================================
class Student {
	private:
		const char * m_name;		// 姓名
		int 		 m_age;			// 年龄
		float		 m_score;		// 分数

	public:
		Student (const char * name, int age, float score) :
			m_name(name),
			m_age(age),
			m_score(score)
		{
			printf("-> 学生 %s 已添加 \n", name);
		}

		friend void show (Student *pstu);				// 声明非成员函数为友元函数
};

/* show 的实现 */
void show (Student *pstu) {
	printf("-> Name: %s,  Age: %d,  Score: %.2f \n", pstu->m_name, pstu->m_age, pstu->m_score);
}

================================ 程序示例 ================================
int main ()
{
	Student stu("张三", 16, 82.5f);
	show(&stu);
	
	return 0;
}
================================ 运行结果 ================================
-> 学生 张三 已添加 
-> Name: 张三,  Age: 16,  Score: 82.50

3. 示例2:成员函数声明为友元函数

??不仅可以声明非成员函数为友元函数,别的类的成员函数也可以声明为本类的友元函数,以访问本类的非公成员。

================================ 定义示例 ================================
class Student;		// 预先声明类 Student, 以定义参数 'Student *pstu'

class Teacher {
	private:
		const char * m_name;
		int			 m_age;

	public:
		Teacher (const char * name, int age) :
			m_name(name),
			m_age(age)
		{
			printf("-> 老师 %s 已添加 \n", name);
		}

		void check (Student *pstu);		// 声明成员函数 check
		void teach (Student *pstu);		// 声明成员函数 teach
};

class Student {
	private:
		const char * m_name;		// 姓名
		int 		 m_age;			// 年龄
		float		 m_score;		// 分数

	public:
		Student (const char * name, int age, float score) :
			m_name(name),
			m_age(age),
			m_score(score)
		{
			printf("-> 学生 %s 已添加 \n", name);
		}

		friend void show (Student *pstu);				// 声明非成员函数为友元函数
		friend void Teacher::check (Student *pstu);		// 声明别的类的成员函数为友元函数
		friend void Teacher::teach (Student *pstu);		// 声明别的类的成员函数为友元函数
};

/* show 的实现 */
void show (Student *pstu) {
	printf("-> Name: %s,  Age: %d,  Score: %.2f \n", pstu->m_name, pstu->m_age, pstu->m_score);
}

/* check 的实现 */
void Teacher::check (Student *pstu) {
	if((pstu->m_score > 60)) {
		printf("-> 学生 %s 成绩合格, 当前成绩: %.2f \n", pstu->m_name, pstu->m_score);
	}
	else {
		printf("-> 学生 %s 成绩不合格, 当前成绩: %.2f \n", pstu->m_name, pstu->m_score);
	}
}

/* teach 的实现 */
void Teacher::teach (Student *pstu) {
	if(pstu->m_score < 70) {
		pstu->m_score += 10;
		printf("-> %s 的教学效果显著, %s 的成绩大幅提升! \n", m_name, pstu->m_name);
	}
	else if (pstu->m_score < 90) {
		pstu->m_score += 5;
		printf("-> %s 的教学效果不错, %s 的成绩小幅提升! \n", m_name, pstu->m_name);
	}
}

================================ 程序示例 ================================
int main ()
{
	Student stu("张三", 16, 82.5f);
	show(&stu);
	Teacher tch("张老师", 26);
	tch.teach(&stu);
	tch.check(&stu);
	
	return 0;
}
================================ 运行结果 ================================
-> 学生 张三 已添加
-> Name: 张三,  Age: 16,  Score: 82.50
-> 老师 张老师 已添加
-> 张老师 的教学效果不错, 张三 的成绩小幅提升!
-> 学生 张三 成绩合格, 当前成绩: 87.50

4. 示例3:类声明为友元类

??在 示例2 中我们在类 Student 中声明了两个 Teacher 类中的成员函数为友元函数,从而让它们可以访问 Student 中的私有成员,在这里我们将换一种方法,通过声明友元类来实现完全相同的效果。

================================ 定义示例 ================================
class Student;		// 预先声明类 Student, 以定义参数 'Student *pstu'

class Teacher {
	private:
		const char * m_name;
		int			 m_age;

	public:
		Teacher (const char * name, int age) :
			m_name(name),
			m_age(age)
		{
			printf("-> 老师 %s 已添加 \n", name);
		}

		void check (Student *pstu);		// 声明成员函数 check
		void teach (Student *pstu);		// 声明成员函数 teach
};

class Student {
	private:
		const char * m_name;		// 姓名
		int 		 m_age;			// 年龄
		float		 m_score;		// 分数
		
		friend class Teacher;		// 声明友元类 Teacher
		
	public:
		Student (const char * name, int age, float score) :
			m_name(name),
			m_age(age),
			m_score(score)
		{
			printf("-> 学生 %s 已添加 \n", name);
		}

		friend void show (Student *pstu);				// 声明非成员函数为友元函数
};

/* show 的实现 */
void show (Student *pstu) {
	printf("-> Name: %s,  Age: %d,  Score: %.2f \n", pstu->m_name, pstu->m_age, pstu->m_score);
}

/* check 的实现 */
void Teacher::check (Student *pstu) {
	if((pstu->m_score > 60)) {
		printf("-> 学生 %s 成绩合格, 当前成绩: %.2f \n", pstu->m_name, pstu->m_score);
	}
	else {
		printf("-> 学生 %s 成绩不合格, 当前成绩: %.2f \n", pstu->m_name, pstu->m_score);
	}
}

/* teach 的实现 */
void Teacher::teach (Student *pstu) {
	if(pstu->m_score < 70) {
		pstu->m_score += 10;
		printf("-> %s 的教学效果显著, %s 的成绩大幅提升! \n", m_name, pstu->m_name);
	}
	else if (pstu->m_score < 90) {
		pstu->m_score += 5;
		printf("-> %s 的教学效果不错, %s 的成绩小幅提升! \n", m_name, pstu->m_name);
	}
}

================================ 程序示例 ================================
int main ()
{
	Student stu("张三", 16, 82.5f);
	show(&stu);
	Teacher tch("张老师", 26);
	tch.teach(&stu);
	tch.check(&stu);
	
	return 0;
}
================================ 运行结果 ================================
-> 学生 张三 已添加
-> Name: 张三,  Age: 16,  Score: 82.50
-> 老师 张老师 已添加
-> 张老师 的教学效果不错, 张三 的成绩小幅提升!
-> 学生 张三 成绩合格, 当前成绩: 87.50



  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:00:54  更:2022-05-07 11:01:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 1:34:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码