什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?

1)什么是 C++ 中的友元函数和友元类?

友元的目的就是让一个函数或者类 访问另一个类中私有成员

友元的关键字为 friend(友元定义时,无需加关键字friend)声明时必须加friend

  • 优点:可以通过友元在类外访问类内的私有 和 受保护类型的成员
  • 缺点:破坏了类的封装性

友元函数:

  • 是定义在类外部的普通函数,但可以访问该类的私有成员。
  • 作用是在某些情况下,需要让外部函数访问类的私有数据,提高程序的灵活性。

友元类:

  • 一个类可以将另一个类声明为友元类。
  • 友元类中的所有成员函数都可以访问另一个类的私有成员。
#include<iostream>
using namespace std;
class A
{
	
	int num;
public:
	friend void fun();  //友元函数
	friend class B;
	A()
	{
		num = 0;
	}
};

A a;
void fun()
{
	a.num = 2;
	cout << a.num << endl;
}
 
class B
{
public:
	void fun()
	{
		a.num = 2;
	}
};
int main()
{
	fun();
}

2)友元的作用是什么?有什么注意事项?

友元的作用:

允许特定的外部函数或类访问类的私有成员,提供了一种在不破坏封装性的前提下,实现更灵活的代码交互的方式。

注意事项:

  • 友元破坏了类的封装性,应谨慎使用,过多使用友元可能导致程序的可维护性降低。
  • 友元关系不能被继承,即如果类 B 是类 A 的友元,类 C 继承自类 A,类 B 不是类 C 的友元。

友元的作用

  • 增强灵活性:在某些情况下,虽然某个函数或类不是一个类的成员函数,但却需要频繁地访问该类的私有或保护成员。通过将其声明为友元,可以在不改变类的封装性的前提下,给予其访问权限,从而提高了代码的灵活性和可扩展性。例如,在实现一个复数类时,可能需要定义一个非成员函数来计算两个复数的乘积。这个函数需要访问复数类的私有成员变量来进行计算,此时可以将该函数声明为复数类的友元函数,以便其能够访问复数类的私有成员。
  • 提高效率:对于一些需要频繁访问类的私有成员的操作,如果通过公有成员函数来访问,可能会增加函数调用的开销。而使用友元函数或友元类,可以直接访问私有成员,从而提高了程序的执行效率。例如,在一个矩阵类中,为了实现矩阵的乘法运算,可能需要频繁地访问矩阵类的私有成员数组来进行计算。如果将矩阵乘法函数声明为矩阵类的友元函数,就可以直接访问矩阵类的私有成员数组,而不需要通过公有成员函数来间接访问,从而提高了矩阵乘法运算的效率。
  • 实现不同类之间的协作:友元可以用于建立不同类之间的紧密协作关系,使得它们能够更方便地共享数据和操作。例如,在一个图形绘制系统中,可能有一个图形类和一个绘制工具类。绘制工具类需要访问图形类的私有成员来进行绘制操作,此时可以将绘制工具类声明为图形类的友元类,以便绘制工具类能够访问图形类的私有成员,从而实现图形的绘制功能。

友元的注意事项

  • 破坏封装性:虽然友元机制提供了一定的灵活性,但过度使用友元会破坏类的封装性。因为友元函数或友元类可以直接访问类的私有成员,这可能会导致类的内部实现细节暴露给外部,增加了代码的耦合度,不利于代码的维护和修改。因此,在使用友元时,应该谨慎考虑,只在必要的情况下才使用友元机制。
  • 单向性:友元关系是单向的,即如果类A是类B的友元,并不意味着类B也是类A的友元。这一点在使用友元时需要特别注意,以免出现意外的访问权限问题。例如,在一个学生类和一个教师类的关系中,教师类可能需要访问学生类的私有成员来查看学生的成绩等信息,因此可以将教师类声明为学生类的友元类。但是,学生类并不需要访问教师类的私有成员,因此学生类不需要是教师类的友元类。
  • 友元声明的位置:友元声明必须放在类的内部,并且在需要访问私有成员的函数或类之前进行声明。一般来说,友元声明可以放在类的公有部分、私有部分或保护部分,其作用域仅限于声明它的类。例如,在一个类的公有部分声明了一个友元函数,那么这个友元函数就可以访问该类的公有成员和私有成员。如果在类的私有部分声明了一个友元函数,那么这个友元函数只能在类的成员函数中被调用,而不能在类的外部被调用。
  • 友元函数和友元类的定义:友元函数和友元类的定义与普通的函数和类的定义相同,但是在友元函数和友元类的定义中,可以直接访问声明它为友元的类的私有成员和保护成员。需要注意的是,友元函数和友元类的定义并不需要使用关键字“friend”,只有在类的声明中才需要使用“friend”关键字来声明友元。
  • 继承与友元:友元关系不会被继承,即如果类B是类A的友元,类C继承自类A,那么类B并不是类C的友元。这是因为友元关系是基于类的具体定义而不是基于类的继承关系。因此,在使用继承和友元时,需要特别注意友元关系的变化,以免出现意外的访问权限问题。
### 为什么 C++ 中的友元函数必须在类内部声明? 在 C++ 中,友元函数是一种特殊的非成员函数,它可以访问类的私有(private)受保护(protected)成员。为了实现这一特性,友元函数必须在类的定义内部通过 `friend` 关键字进行声明。这一机制的设计并非随意,而是出于语言规范、访问控制代码可读性等多方面的考虑。 #### 明确访问权限的授予 类的封装机制决定了其私有受保护成员只能被类内部的成员函数访问。为了允许非成员函数访问这些成员,C++ 引入了友元机制。只有在类定义中显式声明某个函数为友元,编译器才能确认该函数拥有访问权限。这种机制确保了访问控制的严谨性,防止外部函数随意访问类的内部状态,从而维护了封装性[^1]。 例如,以下代码中,`displayData` 被声明为 `MyClass` 的友元函数,因此它可以访问 `MyClass` 的私有成员 `data`: ```cpp class MyClass { private: int data; public: MyClass(int value) : data(value) {} friend void displayData(const MyClass& obj); }; void displayData(const MyClass& obj) { std::cout << obj.data << std::endl; // 合法:displayData 是 MyClass 的友元 } ``` #### 编译器识别与处理机制 C++ 编译器在处理类定义时,需要明确哪些函数被授予访问权限。如果友元函数不在类内部声明,编译器将无法识别其特殊访问权限,导致编译错误。因此,类内部的 `friend` 声明是编译器正确处理访问控制的关键依据[^2]。 #### 增强代码的可读性可维护性 在类定义中声明友元函数,能够清晰地表达设计者的意图:即哪些非成员函数被授权访问类的私有成员。这种显式声明提高了代码的可读性,使得其他开发者可以快速理解类与友元函数之间的关系,从而更有效地维护扩展代码。 例如,在以下代码中,`BB::B1` 被声明为 `AA` 的友元,而 `BB::B2` 则不是,因此只有 `B1` 可以访问 `AA` 的私有成员 `a_`: ```cpp class AA; class BB { public: void B1(AA t); void B2(AA t); }; class AA { friend void BB::B1(AA t); private: int a_; public: AA(int a) : a_(a) {} }; void BB::B1(AA t) { std::cout << t.a_ << std::endl; // 合法 } void BB::B2(AA t) { std::cout << t.a_ << std::endl; // 非法:B2 不是 AA 的友元 } ``` #### 与友元类成员函数友元的关系 除了友元函数之外,C++ 还支持友元类成员函数作为友元。与友元函数类似,这些友元也必须在类定义中通过 `friend` 声明。例如,将一个类声明为另一个类的友元,意味着前者的所有成员函数都可以访问后者的私有受保护成员。这种统一的友元声明机制,使得访问控制逻辑保持一致,增强了语言设计的规范性[^3]。 --- ### 总结 友元函数必须在类内部声明,以明确授予其访问权限,确保编译器能够正确识别并处理访问控制,同时提高代码的可读性可维护性。这一机制是 C++ 封装特性的补充,而非破坏。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值