现代c++第2.3章 友元函数

发布时间:2026/10/9 7:59:55

现代c++第2.3章 友元函数 先澄清一个容易混淆的点C 里没有「static class」这个语法。你在 C# 里写的static class MathHelper或者 Java 里的static class Inner在 C 里都不存在对应的关键字。C 的static放在不同位置含义完全不同写法位置含义class X { static int n; }类的静态成员属于类不属于对象class X { static void f(); }静态成员函数没有 this 指针static int g;全局/命名空间作用域内部链接只在本翻译单元可见void f() { static int c; }局部静态变量程序生命周期、首次执行时初始化static class X {};编译错误C 不允许下面按这几类分别说规则。一、类内的 static 数据成员1. 声明和定义要分开C17 之前classCounter{staticinttotal;// 声明在类体内};intCounter::total0;// 定义必须在且只能在一个 .cpp 里类体内的只是声明不算定义除了下面第 3 条的特例。漏掉类外定义链接时会报 undefined reference。C17 起可以用inline直接在类体内定义不用写.cppclassCounter{inlinestaticinttotal0;// C17等价于 inline 定义};2. 不属于任何对象所有实例共享一份sizeof(Counter)不包含它。即使一个对象都没创建它也存在程序启动时完成静态初始化。访问推荐用Counter::total虽然obj.total也合法但不推荐容易误以为是实例成员。3. 可以在类体内直接给初始值的例外const或constexpr的整型/枚举静态成员C98 起。constexpr静态成员C11 起隐含 inline。任何类型的inline static成员C17 起。classBuf{staticconstexprintSIZE1024;// OKinlinestaticstd::string namex;// C17 OK};注意const static成员如果被odr-use比如取地址Buf::SIZE、绑定到引用仍然需要一个类外的定义。4. 可以是自身类的不完整类型classNode{staticNode instance;// OK静态成员不计入类大小// Node child; // 错误非静态成员不能是不完整类型};5. 访问控制照样生效。private static成员只能在类内和友元里访问这点和实例成员一样。6. 继承与模板静态成员会被派生类继承也可以被同名成员隐藏但不能被 override重写是 virtual 的事。类模板的静态成员每个实例化版本各有一份Fooint::count和Foodouble::count是两个变量。二、static 成员函数核心规则没有 this 指针。因此不能直接访问非静态成员变量/函数必须通过对象或指针obj.x、p-f()。反过来它可以访问私有的非静态成员因为它仍是类的成员受友元规则保护。不能加 cv 限定和引用限定static void f() const是错的。不能是 virtualvirtual static互斥静态调用在编译期就绑定了谈不上多态。类型是普通函数指针void(*)()可以直接当 C 风格回调传进去而非静态成员函数指针类型是void(Class::*)()两者不兼容——这是静态成员函数做回调的最大优势。classTimer{public:staticvoidonTick(void*self);// 可传给 C APIprivate:intinterval;// 靠 self 参数反取};三、类外的 static文件作用域全局或命名空间里的static变量/函数 内部链接只在当前.cpp可见不会和其他翻译单元冲突。staticinthelper();// 只有本文件能看见staticconstintBUF64;两个注意点C17 起更推荐用匿名命名空间代替static全局量namespace { ... }语义更清晰还能放类型定义。头文件里的static const/static constexpr每个包含它的.cpp都会生成一份独立副本。constexpr通常没问题值一样优化后无开销但static的全局对象会有多份实例可能踩坑。四、函数内的局部 staticLoggergetLogger(){staticLogger inst;// 第一次走到这里才构造returninst;}生命周期到程序结束只初始化一次。这就是著名的Meyers Singleton写法。C11 起保证线程安全编译器会插入 once 机制可以放心在多线程里用。C11 之前不行。析构顺序与构造顺序相反且发生在main退出之后。如果某个静态对象的析构函数去用另一个可能已被销毁的静态对象就会崩溃——这是静态对象最常见的线上坑。对策故意不析构new出来不 delete、用指针/std::optional或者避免在析构函数里依赖其他全局状态。五、最麻烦的一条静态初始化顺序同一个翻译单元内按定义顺序初始化。跨翻译单元顺序未定义。// a.cppintxf();// f() 用到了 b.cpp 里的 y// b.cppinty42;// 谁先跑不知道这就是Static Initialization Order Fiasco。通用解法是Construct On First Use把全局量改成返回局部 static 引用的函数见第四节代码把“何时初始化”从链接期推迟到运行期第一次调用。六、那「静态类」在 C 里怎么做如果你想要的是“一组工具函数不需要实例化”C 的惯用做法是命名空间 自由函数而不是硬凑一个类namespacemath{intgcd(inta,intb);}好处没有多余的类名限定、支持 ADL 查找、可以被重载、不会诱导别人去继承或实例化。如果确实要写成类比如要配合模板参数、要封装一堆相关常量常见套路是禁用实例化classMathfinal{Math()delete;// 不能创建对象Math(constMath)delete;Mathoperator(constMath)delete;public:staticintgcd(inta,intb);inlinestaticconstexprdoublePI3.14159265358979;};顺带一提C 的嵌套类天生就相当于 Java 的 static nested class——它不持有外部类的引用也不需要任何static修饰。所以如果你在找“Java static 内部类”的对应物直接用嵌套类即可。七、速查清单容易写错的地方✅ 非 inline 的 static 数据成员必须在一个.cpp里定义别放头文件。✅ C17 优先用inline static省去.cpp的定义。✅ 静态成员函数里不能用this也不能直接碰非静态成员。✅static和virtual、const修饰互斥别一起写。✅ 静态成员函数指针 普通函数指针适合做回调非静态的不行。✅ 跨文件的静态对象初始化顺序未定义用“函数内局部 static”化解。✅ 局部 static 在 C11 后线程安全可放心做单例。✅ 别在静态对象的析构函数里依赖其他全局/静态对象。✅ 想做工具类优先考虑namespace其次才是删掉构造函数的全静态类。在 C 中友元friend的核心作用是打破封装让某个函数或类能够访问另一个类的private和protected成员。虽然它破坏了面向对象编程的封装性但在运算符重载、类之间紧密协作等场景下非常实用。下面为你详细拆解友元函数和友元类的使用方法 友元函数 (Friend Function)友元函数不是该类的成员函数但它可以像成员函数一样访问该类的所有成员。它通常在类内部用friend关键字声明但定义在类的外部。常见用途运算符重载如或、两个不同类之间的数据交换。代码示例#includeiostreamusingnamespacestd;classBox{private:doublewidth;public:Box(doublew):width(w){}// 声明友元函数// 注意友元函数不属于 Box 类所以没有 Box:: 作用域限定符friendvoidprintWidth(Box box);};// 友元函数的定义可以直接访问 Box 的私有成员 widthvoidprintWidth(Box box){coutBox 的宽度是: box.widthendl;}intmain(){Boxbox(10.0);// 像调用普通函数一样调用它printWidth(box);return0;} 友元类 (Friend Class)如果类 A 是类 B 的友元类那么类 A 中的所有成员函数都可以访问类 B 的私有和保护成员。常见用途当一个类需要为另一个类提供底层支持或管理功能时例如链表类访问节点类的私有指针。代码示例#includeiostreamusingnamespacestd;classA;// 前向声明classB{private:intsecret42;public:// 声明类 A 是类 B 的友元friendclassA;};classA{public:voiddisplay(Bb){// 因为 A 是 B 的友元所以可以直接访问 b 的私有成员 secretcoutB 的秘密是: b.secretendl;}};intmain(){A a;B b;a.display(b);return0;} 核心注意事项单向性友元关系是单向的。如果 A 是 B 的友元B 不一定是 A 的友元。不传递友元关系不能继承。如果 A 是 B 的友元B 是 C 的友元A 不一定是 C 的友元。声明位置friend关键字可以放在public、protected或private任何区域效果是一样的。谨慎使用除非确实需要比如重载operator否则尽量少用友元因为它会降低代码的模块化和安全性。需要我帮你写一个用友元函数重载operator让类对象能直接cout输出的完整例子吗
延伸阅读

更多相关文章

2026/10/9 7:54:55

Cloudflare Workers 互调扣费陷阱与 Service Bindings 避坑指南

Cloudflare Workers 跑久了,都会遇到一个很现实的问题:我自己账号下写了两个 Worker,A 需要调 B,那么 A 去请求 B 的 URL,这个“互相请求”到底扣不扣额度里的次数?这个问题我一开始也没当回事,…

2026/10/9 7:54:55

ORB-SLAM3 入门:视觉 SLAM 原理、算法演进与学习路线

摘要:本文面向刚接触视觉 SLAM 或准备阅读 ORB-SLAM3 代码的学习者,系统梳理了视觉 SLAM 的基本原理、算法演进、主要模块与学习路线。内容涵盖 SLAM 要解决的核心问题、单目/双目/RGB-D 深度来源的差异、特征点法与直接法的优化目…

2026/10/9 11:06:27

清理大师的完整思路:深层垃圾定位与持久优化实战

说到“清理大师”,我第一反应是前阵子帮一个朋友处理他卡到怀疑人生的旧手机。那台机子用了快三年,打开微信要转三四秒圈圈,相册滑一滑就掉帧,64G的存储常年飘红。我花了大概一个晚上,没有刷机,没有恢复出厂…

2026/10/9 11:06:27

JavaWeb期末大作业:二手闲置交易系统设计与实现全解析

简介:这是一套面向JavaWeb期末大作业与课程设计的二手闲置物品交易系统完整源码,适合高校计算机相关专业学生参考与二次开发。平台围绕闲置物品的发布、浏览、交易与个人管理等核心场景展开,代码包含用户、商品、订单、留言等模块&#xff0c…

2026/10/9 11:06:27

医疗KBQA问答系统从零搭建:21万实体关系与朴素贝叶斯的闭环实践

简介:面向希望入门知识图谱问答的开发者,整套资源从零搭建了一个医疗领域KBQA问答系统,覆盖7类实体、约3.7万实体与21万实体关系,可完整体验意图识别、实体抽取、图谱构建和答案检索等核心流程,适合作为学习或演示项目…

2026/10/9 11:01:26

求解器并发架构:进程与线程的边界与协同

很多跑算法或做工程的同学,嘴上挂着“并发”和“多线程”,一到真正碰求解器这类计算密集型任务,就翻车。要么内存爆炸,要么直接死锁卡死,要么 CPU 都跑满了但业务吞吐量上不去。这些问题的根源,往往不是数学…

2026/10/8 10:03:18

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

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

2026/10/8 10:03:20

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

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

2026/10/8 6:05:44

无源低通滤波器设计实战:从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/9 0:04:27

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略

毕业论文初稿完成后首次进行AIGC疑似度自查的摸底与分流策略当数万字的学位论文初稿经历开题、实验、问卷与多轮文献梳理最终成形时,绝大多数研究生都会面临一道全新的形式审查关卡:AIGC 疑似度排查。在高校毕业审核流程中,盲审前的文本检测通…

2026/10/9 0:04:27

食堂节能改造源头工厂,商用厨房设备焕新方案广受好评

商用厨房作为餐饮经营、单位供餐的核心后勤阵地,其设备配置、动线规划与运维体系直接决定后厨作业效率、运营成本与合规性。从基础的灶具、制冷存储设备,到油烟净化、水处理等配套系统,每一个环节的合理性都与食品安全、能耗管控、消防安全挂…

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

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

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