C++中的friend函数详细解析

发布时间:2026/10/4 12:36:38

C++中的friend函数详细解析 为什么要使用友元函数在实现类之间数据共享时减少系统开销提高效率。如果类A中的函数要访问类B中的成员例如智能指针类的实现那么类A中该函数要是类B的友元函数。具体来说为了使其他类的成员函数直接访问该类的私有变量。即允许外面的类或函数去访问类的私有变量和保护变量从而使两个类共享同一函数。实际上具体大概有下面两种情况需要使用友元函数1运算符重载的某些场合需要使用友元。2两个类要共享数据的时候。使用友元函数的优缺点优点能够提高效率表达简单、清晰。缺点友元函数破环了封装机制尽量不使用成员函数除非不得已的情况下才使用友元函数。C中的友元机制允许类的非公有成员被一个类或者函数访问友元按类型分为三种普通非类成员函数作为友元,类的成员函数作为友元类作为友元。友元包括友元的声明以及友元的定义。友元的声明默认为了extern就是说友元类或者友元函数的作用域已经扩展到了包含该类定义的作用域所以即便我们在类的内部定义友元函数也是没有关系的。友元可以是一个函数该函数被称为友元函数友元也可以是一个类该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看它与普通函数一样即在定义上和调用上与普通函数一样。友元函数的实现可以在类外定义但必须在类内部声明友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数它不属于任何类但需要在类的定义中加以声明声明时只需在友元的名称前加上关键字friend。我们已知道类具有封装和信息隐藏的特性。只有类的成员函数才能访问类的私有成员程序中的其他函数是无法访问私有成员的。非成员函数可以访问类中的公有成员但是如果将数据成员都定义为公有的这又破坏了隐藏的特性。另外应该看到在某些情况下特别是在对某些成员函数多次调用时由于参数传递类型检查和安全性检查等都需要时间开销而影响程序的运行效率。为了解决上述问题提出一种使用友元的方案。友元是一种定义在类外部的普通函数但它需要在类体内进行说明为了与该类的成员函数加以区别在说明时前面加以关键字friend。友元不是成员函数但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率即减少了类型检查和安全性检查等都需要的时间开销但是它破坏了类的封装性和隐藏性使得非成员函数可以访问类的私有成员。1.普通的非成员函数友元1234567891011121314151617181920212223242526272829303132333435363738#include cmath#include iostreamusingnamespacestd;classPoint{public:Point(doublexx,doubleyy){xxx;yyy;}voidGetXY();frienddoubleDistance(Point a,Point b);protected:private:doublex,y;};voidPoint::GetXY(){//cout(this-x,this-y)endl;cout(x,y)endl;}doubleDistance(Point a,Point b){doublelength;lengthsqrt((a.x-b.x)*(a.x-b.x)(a.y-b.y)*(a.y-b.y));//它可以引用类中的私有成员returnlength;}intmain(void){Point p1(3.0,4.0),p2(6.0,8.0);p1.GetXY();//成员函数的调用方法通过使用对象来调用p2.GetXY();doubled Distance(p1,p2);//友元函数的调用方法同普通函数的调用一样不要像成员函数那样调用coutdendl;system(pause);return0;}说明在该程序中的Point类中说明了一个友元函数Distance()它在说明时前边加friend关键字标识它不是成员函数而是友元函数。它的定义方法与普通函数定义一样而不同于成员函数的定义因为它不需要指出所属的类。但是它可以引用类中的私有成员函数体中的a.xb.xa.yb.y都是类的私有成员它们是通过对象引用的。在调用友元函数时也是同普通函数的调用一样不要像成员函数那样调用。本例中p1.Getxy()和p2.Getxy()这是成员函数的调用要用对象来表示。而Distance(p1, p2)是友元函数的调用它直接调用不需要对象表示它的参数是对象。(该程序的功能是已知两点坐标求出两点的距离。)下面对上面的代码进行输入、输出流的重载1234567891011121314151617181920212223242526272829303132333435363738394041424344454647#include cmath#include iostreamusingnamespacestd;classPoint{public:Point(doublexx,doubleyy){xxx;yyy;}voidGetXY();frienddoubleDistance(Point a,Point b);friendostream operator (ostream a,Point b);protected:private:doublex,y;};// friend ostream operator(ostream o,A another);ostream operator (ostream out,Point b)//在类中声明的时候可以是ostream a函数定义的时候也可以是ostream out{out(b.x,b.y)endl;returnout;}voidPoint::GetXY(){//cout(this-x,this-y)endl;//cout(x,y)endl;cout*this;}doubleDistance(Point a,Point b){doublelength;lengthsqrt((a.x-b.x)*(a.x-b.x)(a.y-b.y)*(a.y-b.y));returnlength;}intmain(void){Point p1(3.0,4.0),p2(6.0,8.0);p1.GetXY();p2.GetXY();doubled Distance(p1,p2);coutdendl;system(pause);return0;}2.类作为友元类作为友元需要注意的是友元类和原始类之间的相互依赖关系如果在友元类中定义的函数使用到了原始类的私有变量那么就需要在友元类定义的文件中包含原始类定义的头文件。但是在原始类的定义中包含友元类声明的那个类就不需要包含友元类的头文件.另外不需要在类定义前去声明友元类因为友元类的声明自身就是一种声明。1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556//A.h#pragma once#include iostreamusingnamespacestd;classA{//friend class B; //如果不写这句话将会出现编译错误public:~A(void);A();private:intm_nItem;};//A.cpp#include A.hA::A(){m_nItem 3;}A::~A(void){}//B.h#pragma onceclassB{public:B(void);~B(void);intfunc();};//B.cpp#include StdAfx.h#include B.h#include A.h //must include A.h#include iostreamB::B(void){}B::~B(void){}intB::func(){coutThis is in Bendl;A a;returna.m_nItem;}3.类成员函数作为友元函数这个稍微有点复杂因为你要类成员函数作为友元你在声明友元的时候要用类限定符所以必须先定义包含友元函数的类但是在定义友元的函数时候又必须事先定义原始类。通常的做法先定义包含友元函数的类再定义原始类这个顺序不能乱。(如果是友元类则没有这种这种必须)如下面所示12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849//A.h#pragma once#include B.hclassA{friendintB::func(A xx);public:A(void):mx(20),my(30){}~A(void){}private:intmx;intmy;};//B.h#pragma onceclassA;classB{public:B(void);~B(void);intfunc(A xx);};//B.cpp#include B.h#include A.hB::B(void){}B::~B(void){}intB::func(A xx){returnxx.mx * xx.my;}//main.cpp#include A.h#include B.h#include iostreamusingnamespacestd;voidmain(){A a;B b;coutb.func(a)endl;system(pause);}4. 友元不具有相互性只具有单项性若类B是类A的友元类A不一定是类B的友元要看在类中是否有相应的声明。5. 友元不能被继承B是A的友元类C是B的子类推不出C是A的友元6. 友元不具有传递性B是A的友元C是B的友元推不出C是A的友元7. 友元函数的使用技巧在用C实现单例模式时可以利用友元函数实例化对象。然后把类的构造函数和析构函数都设计成私有函数。1234567891011121314151617classCMySingleton{public:friendCMySingleton InstanceMEC();private:CMySingleton() {};CMySingleton(constCMySingleton lxSington) {};~CMySingleton(){};};CMySingleton InstanceMEC(){//因为函数InstanceMEC()是类ClxSingletonMEC的友元函数所以可以访问类所有的成员函数.所以不会有编译错误staticCMySingleton Instance;returnInstance;}以上就是本文的全部内容希望对大家的学习有所帮助
延伸阅读

更多相关文章

2026/10/4 12:31:38

多编码代理模型切换混乱?用菜单栏统一编排二十多个代理

1. 从二十多个编码代理的切换混乱说起如果你同时用过三款以上的编码代理工具,大概率经历过这种场景:左边窗口跑着一个负责补全的,右边终端挂着一个负责重构的,浏览器里还开着第三个在生成测试用例。每个工具都有自己的模型选择入口…

2026/10/4 12:31:38

智慧校园管理系统毕设:Java+小程序+MySQL 跑通与避坑指南

简介:这是一套面向高校毕业设计与课程设计的智慧校园管理系统完整源码包,采用微信小程序作为前端、Java作为后端服务,并搭配MySQL 5.7数据库。系统覆盖用户身份认证、课表查询、校园活动、成绩查询、校园卡管理等典型模块,适合需要…

2026/10/4 12:31:38

学生公寓组网设计全攻略:VLAN规划、交换机配置与DHCP实践

简介:这份计算机网络课程设计报告以学生公寓组网为真实课题,面向网络工程专业学生、课程设计者及校园网规划人员,覆盖需求分析、组网原则、拓扑方案与安全策略等完整设计环节。报告完整呈现了从需求分析到方案落地的过程,包括核心…

2026/10/4 21:57:03

Zabbix交换机监控模板实战:SNMP协议与LLD端口发现避坑指南

简介:面向Zabbix网络运维人员的交换机监控模板资源,解决手动配置SNMP监控项繁琐、效率低的问题。压缩包内共2个XML模板文件,整体仅3KB,分别适用于SNMP v1与v2公共协议,便于兼容不同交换机的SNMP配置环境。模板预设了端…

2026/10/4 21:52:03

Qwen2-VL图像识别微调实战:Python实现LoRA训练与部署指南

简介:面向图像识别与多模态大模型应用开发者,这份Python工程源码完整演示了基于千问Qwen2-VL从COCO 2014 Caption图片数据准备、模型训练到checkpoint加载推理的落地路径,适合已有Python基础、希望掌握视觉语言模型微调及图像识别工程化流程的…

2026/10/4 0:01:02

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/4 1:01:05

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 0:01:02

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/4 0:01:02

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/4 1:01:05

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑