C++第18课:友元函数与友元类
友元的概念
在 C++ 中,类的一个重要特性就是封装,通过将数据成员和成员函数分为私有(private)、保护(protected)和公有(public)三种访问级别,实现对类内部数据的保护和隐藏。私有成员只能被类自身的成员函数所访问,外部函数和其他类无法直接访问。
但在某些特定的场景下,需要打破这种限制,让特定的函数或类能够访问这些私有成员。就好比在现实生活中,虽然我们会保护自己的隐私,但对于特别信任的朋友,我们愿意与他们分享一些秘密。C++ 中的友元机制,正是为了满足这样的需求而诞生的。通过友元,我们可以授予其他函数或类对本类私有成员的访问权限 ,让它们像类的成员函数一样自由地访问私有数据。这为我们在编程时提供了更大的灵活性,使得代码的设计和实现更加高效。
友元主要分为两种类型:友元函数(Friend Function)和友元类(Friend Class)。友元函数是一个非成员函数,但它可以访问类的私有和保护成员;友元类则是一个类,其所有成员函数都能访问另一个类的私有和保护成员。
友元函数
1.定义与声明
友元函数是在类外部定义的函数,但它被授予了访问类的私有和保护成员的特殊权限。在类中声明友元函数时,需要使用 friend 关键字。声明语法如下:
class MyClass {private:int privateData;public:// 声明友元函数,这里的函数可以是全局函数,也可以是其他类的成员函数friend void friendFunction(MyClass& obj);};
如果是将全局函数声明为友元函数,在类外定义时和普通函数定义方式相同,不需要使用类名和作用域解析运算符 ::;如果是将其他类的成员函数声明为友元函数 ,定义时需要加上所属类名和作用域解析运算符。不过,不能把其他类的私有成员函数声明为友元函数,因为私有成员函数的访问权限限制,在类外无法调用,即使声明为友元也没有实际意义。
2. 函数特性
友元函数有一个非常独特的特性,它不属于类的成员函数,却能访问类的私有和保护成员 ,就好像是被类邀请到内部的特殊访客。这一点打破了类的常规访问规则,让友元函数拥有了特殊的 “通行证”。虽然它能访问类的私有成员,但它本身的返回类型和参数列表并不受类的影响,仍然按照普通函数的规则来定义和使用。
3.应用案例
#include <iostream>class Rectangle {private:int width;int height;public:Rectangle(int w, int h) : width(w), height(h) {}// 声明友元函数friend int calculateArea(Rectangle& rect);};// 友元函数的定义,在类外实现int calculateArea(Rectangle& rect) {return rect.width * rect.height;}int main() {Rectangle rect(5, 3);// 调用友元函数计算矩形面积int area = calculateArea(rect);std::cout << "矩形的面积是: " << area << std::endl;return 0;}
在这个例子中,calculateArea 函数被声明为 Rectangle 类的友元函数,因此它可以直接访问 Rectangle 类的私有成员 width 和 height 来计算矩形的面积。
4.应用场景
友元函数可以在很多场景中得到应用,一个常见的应用场景是运算符重载。例如,当我们想要重载二元运算符(如 +、-、== 等)时,如果运算符的左右操作数属于不同的类,使用友元函数可以更方便地实现运算符的功能 ,因为它能够同时访问两个类的私有成员,从而简化运算的实现过程。
在一些需要从外部函数访问类的内部实现细节,而又不想通过繁琐的公有接口来访问时,友元函数也能派上用场。它可以精简代码,提高程序的执行效率 ,避免了通过公有接口访问时可能带来的额外开销,比如参数传递、类型检查等操作的时间消耗。
友元类
1.定义与声明
友元类是一种特殊的类关系,当一个类被声明为另一个类的友元类时,友元类的所有成员函数都可以访问目标类的私有和保护成员 。声明友元类的语法如下:
class TargetClass {private:int privateData;public:// 声明友元类friend class FriendClass;};
在这个例子中,FriendClass 被声明为 TargetClass 的友元类,这意味着 FriendClass 的任何成员函数都能够访问 TargetClass 的私有成员 privateData 。这种声明方式就像是在告诉 TargetClass:“FriendClass 是我非常信任的伙伴,它可以随意访问我的私有数据。”
2.友元类特性
友元类与友元函数有所不同,它是一种类级别的友元关系 。一旦一个类被声明为另一个类的友元类,那么友元类中的每一个成员函数都自动拥有了访问目标类私有和保护成员的权限,无需再对每个成员函数单独进行声明 。这就好比是一个团队(友元类)作为一个整体被赋予了访问另一个团队(目标类)内部机密的权限,团队里的每一个成员都可以自由地查看和使用这些机密数据。
3.应用案例
#include <iostream>class BankAccount {private:double balance;public:BankAccount(double initialBalance) : balance(initialBalance) {}// 声明BankManager为友元类friend class BankManager;};class BankManager {public:// 查看账户余额的成员函数void checkBalance(BankAccount& account) {std::cout << "账户余额是: " << account.balance << std::endl;}// 修改账户余额的成员函数void modifyBalance(BankAccount& account, double amount) {account.balance += amount;std::cout << "账户余额已更新为: " << account.balance << std::endl;}};int main() {BankAccount account(1000.0);BankManager manager;manager.checkBalance(account);manager.modifyBalance(account, 500.0);return 0;}
在这个示例中,BankManager 类被声明为 BankAccount 类的友元类。因此,BankManager 类的成员函数 checkBalance 和 modifyBalance 可以直接访问 BankAccount 类的私有成员 balance ,分别实现了查看账户余额和修改账户余额的功能。
4.应用场景
友元类在多个类之间存在紧密合作关系时非常有用 。例如,在实现一个复杂的数据结构,如链表或树时,可能会有一个节点类和一个管理类。管理类需要频繁地访问节点类的私有成员来进行插入、删除、查找等操作 ,此时将管理类声明为节点类的友元类,可以简化代码的编写,提高程序的执行效率 ,因为无需通过繁琐的公有接口来进行这些操作,减少了函数调用的开销和代码的复杂性。
使用友元的注意事项
尽管友元机制为我们在 C++ 编程中提供了很大的便利,但如果使用不当,也可能带来一些问题。友元机制在一定程度上打破了类的封装性 ,这虽然为实现某些功能提供了便利,但也降低了代码的安全性和可维护性 。因为友元函数和友元类可以直接访问类的私有成员,这就意味着这些私有成员的访问不再受到类的访问控制的严格约束 ,如果在程序中随意使用友元,可能会导致代码的结构变得混乱,难以理解和调试 。
所以,在使用友元时,一定要谨慎行事。只有在确实需要打破封装,让外部函数或类访问私有成员的情况下,才考虑使用友元 。并且要尽量将友元的使用范围限制在最小程度,只授予它们访问所需成员的最少权限 ,避免不必要的访问,以减少对封装性的破坏 。例如,在前面提到的矩形面积计算的例子中,如果我们可以通过其他方式(如提供公有成员函数来获取矩形的宽和高)来实现面积计算功能,就不应该轻易使用友元函数。只有当这种方式确实无法满足需求,或者会导致代码变得非常复杂时,才考虑使用友元函数来直接访问私有成员 。
更多推荐
所有评论(0)