一、友元类简介




1、友元类引入


在 C++ 语言中 , " 友元类 " 是 一个类 与 另外一个类 的 特殊类关系累 ,

类 A 的 " 友元类 " B 中 , 可以直接访问 A 类 的 私有成员 和 受保护成员 ;

  • B 是 A 的好朋友 , B 可以访问 A 的所有成员 ;

2、友元类声明


声明一个 类 B 是 另一个类 A 的 友元类 , 可以 在类 A 中使用 friend 关键字来声明 ;

  • B 是 A 的 友元类 ;
  • B 类中定义 A 类型成员变量 ;
  • B 可以访问 A 中的 所有成员 , 包括 私有成员 或 受保护成员 ;
  • B 可以看做 A 的 数据操作辅助类 ;

代码示例 :

class Student
{
private:
	// 声明 StudentCaculate 类是 Student 类的友元类
	// 在 StudentCaculate 类中可以访问 Student 类中的私有成员
	friend class StudentCaculate;
}

3、友元类单向性


友元类单向性 :

友元类关系是单向的 , 声明一个类 B 是 另一个类 A 的 友元类 ,

B 可以访问 A 的 所有成员 ,

但是 A 不是 B 的友元类 , A 不能访问 B 的私有和保护成员 ;


4、友元类继承性


友元类 关系不具有继承性 , 即 子类不能直接继承父类的友元类 ;


5、友元类作用


友元类主要作用 :

  • 作为 某个类的 数据操作 辅助类 ;
  • 作为 多个类 之间 传递信息 的 辅助类 ;




二、友元类和友元函数由来




1、友元类和友元函数引入


友元类 和 友元函数 会破坏 C++ 面向对象 的封装性 , 那么为什么还会出现该机制呢 ?

有些编程场景 , 需要破坏类的封装性 , 需要访问类的私有属性 ;

  • Java 中给出的方案是 反射机制 ;
  • C++ 中给出的方案是 友元函数 和 友元类 ;

2、Java 反射机制


Java 类编译成 class 字节码后 , 可以通过 反射 字节码 的方式 访问 类的私有属性 ;

反射机制 在 特定领域开发 中应用广泛 , 如 SDK , 开发框架 , 逆向 等领域中 ;

反射机制 是 面向切面编程 AOP 的基础 ;

反射机制 成为一种编程标准 ;


3、C / C++ 编译过程


C 代码 和 C++ 代码 , 编译成 so 动态库 或 a 静态库 , 需要如下步骤 :

  • 预编译
  • 编译
  • 汇编
  • 链接

在这里插入图片描述

最终的 函数库 中 都是汇编指令 , 机器码指令 , 如果要从指令中查找指定的类的私有属性 , 该操作难度很大 ;






三、友元类代码示例



在 Student 类中 , 定义了友元类 StudentCaculate ,

	// 声明 StudentCaculate 类是 Student 类的友元类
	// 在 StudentCaculate 类中可以访问 Student 类中的私有成员
	friend class StudentCaculate;

在 StudentCaculate 中 , 定义了 Student 类型成员变量 , 可以访问 Student 对象的所有成员 , 包括 私有成员 和 保护成员 ;


代码示例 :

#include "iostream"
using namespace std;

class Student
{
public:
	// 带参构造函数
	Student(int age = 1, int height = 1)
	{
		this->age = age;
		this->height = height;
		cout << "执行 Student 的构造函数" << endl;
	}

	~Student()
	{
		cout << "执行 Student 的析构函数" << endl;
	}

public:
	// 打印类数据
	void print()
	{
		cout << " age = " << age  << " , height = " << height << endl;
	}

private:
	// 声明 StudentCaculate 类是 Student 类的友元类
	// 在 StudentCaculate 类中可以访问 Student 类中的私有成员
	friend class StudentCaculate;

	// 声明友元函数 
	friend void changeAge(Student* s, int age);

private:
	int age;		// 年龄
	int height;		// 身高
};

class StudentCaculate
{
public:
	void fun()
	{
		cout << "age + height = " << student.age + student.height << endl;
	};
public:
	// 此处会自动调用默认的构造函数
	// 默认值都为 1
	Student student;
};

// 在友元函数中 访问 age 私有属性
void changeAge(Student* s, int age)
{
	s->age = age;
}



int main() {
	
	// 声明 Student 友元类 StudentCaculate 对象
	StudentCaculate sc;

	// 调用 sc 对象中的 fun , 其中调用了 Student 的私有成员
	sc.fun();


	// 为 StudentCaculate 设置一个非默认值
	sc.student = Student(10, 120);

	// 调用 sc 对象中的 fun , 其中调用了 Student 的私有成员
	sc.fun();
	

    // 控制台暂停 , 按任意键继续向后执行
    system("pause");

    return 0;
}

执行结果 :

执行 Student 的构造函数
age + height = 2
执行 Student 的构造函数
执行 Student 的析构函数
age + height = 130
请按任意键继续. . .

在这里插入图片描述

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐