首页 > 编程语言 >什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?

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

时间:2024-11-18 16:14:39浏览次数:3  
标签:友元 函数 私有 成员 C++ 访问 Complex 友元类

友元函数(Friend Function)

定义

友元函数是在类定义中用关键字friend声明的非成员函数。它可以访问类的私有(private)和保护(protected)成员。

作用和使用场景

友元函数主要用于在某些情况下,需要在类的外部函数中访问类的私有或保护成员。例如,在操作符重载中,当需要访问类的私有数据成员来实现特定的操作符功能时,友元函数就很有用。

示例

假设有一个Complex类,表示复数,包含实部real和虚部imaginary两个私有成员变量。我们想实现一个函数来计算两个复数的加法并返回结果。

class Complex {
private:
    double real;
    double imaginary;
public:
    Complex(double r = 0, double i = 0) : real(r), imaginary(i) {}
    friend Complex addComplex(const Complex& c1, const Complex& c2);
};
Complex addComplex(const Complex& c1, const Complex& c2) {
    Complex result;
    result.real = c1.real + c2.real;
    result.imaginary = c1.imaginary + c2.imaginary;
    return result;
}

在这个例子中,addComplex函数是Complex类的友元函数。它可以直接访问Complex类的私有成员real和imaginary,从而实现两个复数的加法运算。

友元类(Friend Class)

定义

友元类是在一个类中用friend关键字声明的另一个类。友元类的所有成员函数都可以访问声明它为友元的类的私有和保护成员。

作用和使用场景

当两个类之间存在紧密的合作关系,需要一个类能够访问另一个类的私有和保护成员来完成特定的功能时,就可以使用友元类。比如,在一个图形绘制系统中,有一个Shape类和一个Renderer类,Renderer类需要访问Shape类的私有成员来正确地绘制形状,此时可以将Renderer类声明为Shape类的友元类。

示例

假设有一个Car类和一个Mechanic类。Mechanic类需要访问Car类的私有成员来进行维修等操作。

class Car {
private:
    int engineStatus;
public:
    Car(int status = 0) : engineStatus(status) {}
    friend class Mechanic;
};
class Mechanic {
public:
    void repairEngine(Car& c) {
        c.engineStatus = 1;  // 可以访问Car类的私有成员engineStatus
    }
};

在这个例子中,Mechanic类是Car类的友元类,Mechanic类中的repairEngine函数可以访问Car类的私有成员engineStatus来修改汽车发动机的状态。

好处:可以通过友元在类外访问类内的私有 和 受保护类型的成员

坏处:破坏了类的封装性

友元的作用

增强灵活性

访问私有成员:在 C++ 中,类的私有成员(private)和保护成员(protected)通常不能被外部函数或其他类访问。友元函数和友元类提供了一种机制,使得外部函数或其他类能够访问这些受限的成员。例如,在实现某些操作符重载函数时,可能需要访问类的私有数据成员来正确地实现操作符的功能。

协同工作:在一些复杂的程序设计场景中,不同的类可能需要紧密协作。比如,一个图形绘制系统中有图形类(如Circle、Rectangle)和绘制工具类(如DrawingTool)。绘图工具类需要访问图形类的内部细节(如圆心坐标、边长等私有数据)来进行精确的绘制,通过将DrawingTool类声明为图形类的友元类,可以方便地实现这种协作。

方便代码实现

提高效率:在某些情况下,使用友元可以避免通过公有接口函数访问私有成员所带来的额外开销。例如,若频繁地通过公有函数获取和设置私有数据成员的值,会涉及函数调用的开销。而友元函数直接访问私有成员,可以减少这种开销,在性能敏感的代码部分可能会很有用。

操作符重载:对于一些自定义类型的操作符重载,友元函数提供了一种自然的方式。例如,对于复数类Complex,要实现+操作符重载来相加两个复数。使用友元函数可以方便地访问两个操作数(复数对象)的私有成员(实部和虚部),使得操作符重载的实现更加简洁直观。

注意事项

破坏封装性

友元机制打破了类的封装原则。类的封装性使得数据隐藏在类内部,只能通过公有接口访问,这有助于保证数据的完整性和安全性。而友元函数和友元类可以直接访问私有和保护成员,这可能会导致代码的可维护性降低。如果滥用友元,可能会使代码变得难以理解和调试,因为外部函数或类对类内部数据的访问不受常规封装规则的限制。

谨慎使用

应该谨慎地决定哪些函数或类需要成为友元。只有在确实有必要访问另一个类的私有或保护成员,并且这种访问是合理的、有助于程序设计的情况下,才应该使用友元。例如,不要仅仅为了方便而随意将大量外部函数或类声明为友元,而应该先考虑是否可以通过改进类的公有接口来满足需求。

双向友元关系的复杂性

当两个类相互声明为友元时(即 A 类是 B 类的友元,同时 B 类也是 A 类的友元),可能会导致复杂的依赖关系。这种双向友元关系可能会使代码的逻辑变得复杂,在修改其中一个类的内部实现时,可能会影响到另一个类。因此,在使用双向友元时,需要特别小心,充分考虑可能产生的后果。

标签:友元,函数,私有,成员,C++,访问,Complex,友元类
From: https://blog.csdn.net/2202_75941514/article/details/143860459

相关文章

  • 打卡信奥刷题(262)用C++信奥P2004[普及组/提高] 领地选择
    领地选择题目描述作为在虚拟世界里统帅千军万马的领袖,小Z认为天时、地利、人和三者是缺一不可的,所以,谨慎地选择首都的位置对于小Z来说是非常重要的。首都被认为是一个占地C×......
  • 代码随想录算法训练营第三十二天| 509. 斐波那契数 、70. 爬楼梯、746. 使用最小花费
    理论基础总结一下就是:动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的。动态规划五部曲确定dp数组(dptable)以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组509.斐波那契数1.......
  • 代码随想录算法训练营第三十三天| 62.不同路径 、63. 不同路径 II、343. 整数拆分 。c
    62.不同路径思路:按照dp五步法分析,成功AC。代码随想录classSolution{publicintuniquePaths(intm,intn){int[][]dp=newint[m+1][n+1];dp[0][1]=1;for(inti=1;i<=m;i++){for(intj=1;j<=n;j++){......
  • C++多线程编程
    一、概念多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。传统的C++(C++11标准之前)中并没有引入线程这个概念,在C++11出来之前,如果我们想要在C++中实现多线程,需要借助操作系统平台提供的API,比如Linux的<pthread.h>,或者windows下的<windows.h>。1.1其......
  • C++ 中的线程、锁和条件变量
    C++中的线程、锁和条件变量Created:2024-06-19T17:17+08:00Published:2024-11-18T10:39+08:00Categories:C-CPP目录线程创建与执行锁lockguardexamplemutex底层实现解释byGPT条件变量(conditionvariable)线程从cv.wait(lock)被唤醒后会自动抢锁虚假唤醒生产者消费......
  • C++二级:数字字符求和
    数字字符求和请编写一个程序实现以下功能:从一个字符串中,提取出所有的数字字符即0-9,并作为数求和。输入一行字符串,长度不超过100,字符串中不含空格。输出字符串中所有数字字符作为数的和样例输入Lsd2f02k3ja3sdf223样例输出171、数字字符求和请编写一个程序实现以下功......
  • C++刷题第十题——求奇数的乘积
    ProblemDescription给你n个整数,求他们中所有奇数的乘积。Input输入数据包含多个测试实例,每个测试实例占一行,每行的第一个数为n,表示本组数据一共有n个,接着是n个整数,你可以假设每组数据必定至少存在一个奇数。Output输出每组数中的所有奇数的乘积,对于测试实例,输出一行。Sa......
  • 《 C++ 修炼全景指南:二十 》不止是链表升级!跳表的核心原理与超强性能解析
    摘要这篇博客全面解析了跳表(SkipList)作为一种高效的链表数据结构的特性和应用。跳表以多层链表和随机化策略实现O(logn)的查找、插入和删除性能,简化了平衡树结构中常见的复杂旋转操作。通过剖析跳表的结构设计和核心操作,我们探讨了其在范围查询和动态更新中的优势,......
  • c++ 后端
    基础知识1.指针、引用2.数组3.缺省参数4.函数重载5.内联函数6.宏7.auto8.const9.类和对象10.类的6个默认成员函数11.初始化列表12.this指针13.C/C++的区别14.C++三大特性15.结构体内存对齐规则16.explicit17.static18.友元类、友元函数19.内部类20.......
  • C++ 编程基础(8)模版 | 8.2、函数模版
    文章目录一、函数模版1、声明与定义2、模版参数3、模板的实例化3.1、隐式实例化3.2、显示实例化4、模版的特化5、注意事项6、总结前言:C++函数模板是一种强大的特性,它允许程序员编写与类型无关的代码。通过使用模板,函数或类可以处理不同的数据类型,而无需重复编写......