发布时间:2026/9/1 6:16:04
C++类和对象(四)—— 初始化列表、类型转换、static、友元、内部类、匿名对象与编译器优化 文章目录1. 再探构造函数1.1 初始化列表1.1.1 初始化列表形式1.1.2 初始化列表的本质1.1.3 初始化列表的先后顺序1.1.4 初始化列表的缺省值1.1.5 两个缺省值对比1.1.6 一定要在初始化列表中显式写的变量1.1.7 初始化列表的总结2 类型转换2.1 单参数隐式类型转换2.2 多参数隐式类型转换2.3 类类型之间的隐式类型转换2.4 expilcit --- 禁用隐式类型转换3 static成员3.1 static成员变量3.1.1 static成员变量初始化的位置3.1.2 static成员变量的从属3.1.3 static成员变量的访问3.1.4 static成员变量不能给缺省值3.2 static成员函数3.2.1 static 成员函数的特点3.2.2 static成员函数和非static成员函数3.2.3 static成员函数的类外访问方式4 友元4.1 友元函数4.1.1 友元函数的作用4.1.2 友元声明4.1.3 友元函数的一对多4.2 友元类4.2.1 友元类的作用4.2.2 友元类没有双向性4.2.3 友元类没有传递性4.2.4 友元类的问题5 内部类5.1 内部类的特点5.2 内部和外部类的关系5.3 内部类的用处6 匿名对象6.1 匿名对象和有名对象6.2 匿名对象的作用6.3 匿名对象和临时对象7 对象拷贝时的编译器优化7.1 两次连续构造7.1.1 正常优化7.1.2激进优化7.2 三次连续构造这里是think的博客希望可以一起交流知识一起think今天我们来学习C类和对象四一起来think1. 再探构造函数1.1 初始化列表1.1.1 初始化列表形式classA{public:A(inta0):_a1(a),_a2(2),_a3(4){coutA(int a)endl;}private:int_a11;int_a2;int_a3;};这里的:_a1(a),_a2(2),_a3(4)就是初始化列表,可以看到初始化列表是以冒号开始对成员变量进行初始化其中以逗号分隔各个成员变量其中可以换行可以不换行建议换行防止一行太长。初始化列表中可以用值初始化成员变量也可以用表达式初始化:p ((int*)malloc(sizeof(int)*6));1.1.2 初始化列表的本质初始化列表可以认为是成员变量定义初始化的地方即private:int_a11;int_a2;int_a3;这里是类成员变量中的声明语法上认为初始化列表是定义时初始化的地方所以既然是定义时初始化的地方那么每一个成员变量都要经过初始化列表。1.1.3 初始化列表的先后顺序初始化列表是定义时初始化的地方但是初始化的顺序并不是按照初始化列表来的而是按照声明顺序来的。1.1.4 初始化列表的缺省值private:int_a11;int_a2;int_a3;这个int _a1 1;就是缺省值即如果初始化列表中没有这个成员变量初始化列表就会用这个来初始化。1.1.5 两个缺省值对比classA{public:A(inta0):_a1(a),_a2(2),_a3(4){coutA(int a)endl;}private:int_a11;int_a2;int_a3;};intmain(){Aa(1);return0;}可以看到初始化列表的缺省值和函数形参的缺省值是比较容易混淆的函数形参的缺省值是在该处没有参数时使用缺省值传递给形参而初始化列表的缺省值则是在没有显示写的时候用缺省的初始化成员变量。1.1.6 一定要在初始化列表中显式写的变量对于const 成员变量引用成员变量没有默认构造的类类型变量一定要在初始化列表中显式写对于前面两个我们都知道是只能在定义时初始化之后就不能修改对应的值了。对于没有默认构造的类类型变量除了在没有默认构造函数的类中补上默认构造函数外解决方法就是在初始化列表中显式初始化了。1.1.7 初始化列表的总结初始化列表分为显式写和不显式写的显式写的就用显式写的来初始化成员变量不显式写的如果有声明处缺省值a就用缺省值没有缺省值b如果是内置类型x一般编译器不做处理但是也可能初始化为0如果是自定义类型y调用它的默认构造函数如果没有默认构造函数就报错。2 类型转换#includeiostreamusingnamespacestd;classA{public:A(inta1):_a1(a1){}//explicit A(int a1, int a2)A(inta1,inta2):_a1(a1),_a2(a2){}voidPrint(){cout_a1 _a2endl;}intGet()const{return_a1_a2;}private:int_a11;int_a22;};classB{public:B(constAa):_b(a.Get()){}private:int_b0;};intmain(){A aa11;aa1.Print();constAaa21;A aa3{2,2};B baa3;constBrbaa3;return0;}2.1 单参数隐式类型转换A aa1 1;语法就是1隐式类型转换为A类型的临时对象这个过程又叫做构造再拷贝构造给aa1因为构造再拷贝构造太繁琐了可以优化所以一般现在的编译都会优化为直接构造即1直接构造aa1。其中const A aa2 1;这里就不会优化了因为没有连续的构造这里就只是1隐式类型转换为A的临时对象构造然后aa2引用这个临时对象。2.2 多参数隐式类型转换在C11中才有多参数隐式类型转换其中单参数是没有括号的而多参数的则是由一个大括号优化也是和单参数一样的。2.3 类类型之间的隐式类型转换classB{public:B(constAa):_b(a.Get()){}private:int_b0;};B baa3;constBrbaa3;return0;这里其实说明了不只是整型才可以隐式类型转换如果参数中有其他类类型的对象类类型之间也是可以隐式类型转换的至于优化和整型是一样的。2.4 expilcit — 禁用隐式类型转换explicit A(int a1, int a2)加上这个关键字后就不能在隐式类型转换了如A aa3 { 2,2 };必须要显式写成这样A aa3(2,2);3 static成员3.1 static成员变量3.1.1 static成员变量初始化的位置static成员要在类外初始化同时初始化的时候不需要加上static声明时加即可因为static即表示该变量存入静态区后续初始化就没有必要再加了。#includeiostreamusingnamespacestd;classA{public:A(inta1):_a1(a1){}staticintGet(){return_a2;}private:int_a11;staticint_a2;};intA::_a2100;intmain(){coutA::Get()endl;return0;}3.1.2 static成员变量的从属static成员变量不同于其他的成员变量static成员变量不属于某一个对象而是被类的所有对象所共享并且static成员变量也不在对象中而是在静态区中。可以认为static成员变量是公共的而其他成员变量是私有的3.1.3 static成员变量的访问static成员变量是公共的那么可以A::_a2;也可以A a; a._a2;(pubilc下才可以这样访问否则要写一个函数来访问这也说明static成员变量受访问限定符的限制当然static成员函数也受限制)3.1.4 static成员变量不能给缺省值由于static成员变量属于类本身所有对象共享同一份而普通成员变量的缺省值是对象初始化时使用的规则每创建一个对象都会根据这个规则初始化自己的成员变量。因此 static 成员变量不适合使用普通成员的缺省初始化方式。3.2 static成员函数3.2.1 static 成员函数的特点普通成员函数属于类但是依赖对象执行所以有 this 指针。static 成员函数属于类但是不依赖对象所以没有 this 指针。3.2.2 static成员函数和非static成员函数static成员函数因为没有this指针所以不能使用除了static成员变量的其他成员变量同时也不能使用非static成员函数。但是非static成员函数可以使用static成员变量和static成员函数。3.2.3 static成员函数的类外访问方式和static成员变量一样static成员函数也是有两种访问方式A::Get();也可以A a; a.Get();作为成员static成员也是受访问限定符的限制的。4 友元4.1 友元函数#includeiostreamusingnamespacestd;classB;classA{// 友元声明friendvoidfunc(constAaa,constBbb);private:int_a11;int_a22;};classB{// 友元声明friendvoidfunc(constAaa,constBbb);private:int_b13;int_b24;};voidfunc(constAaa,constBbb){coutaa._a1endl;coutbb._b1endl;}intmain(){A aa;B bb;func(aa,bb);return0;}在函数声明前面加上一个friend放入类中就成为了这个类的友元函数。4.1.1 友元函数的作用友元函数可以访问该类的私有保护成员但是它不是成员函数也没有this指针。4.1.2 友元声明友元声明可以在类的任意位置不受访问限定符的限制。4.1.3 友元函数的一对多一个函数可以是多个类的友元即我可以是A的朋友也可以是B的朋友。4.2 友元类#includeiostreamusingnamespacestd;classA{// 友元声明friendclassB;private:int_a11;int_a22;};classB{public:voidfunc1(constAaa){coutaa._a1endl;cout_b1endl;}voidfunc2(constAaa){coutaa._a2endl;cout_b2endl;}private:int_b13;int_b24;};intmain(){A aa;B bb;bb.func1(aa);bb.func1(aa);return0;}4.2.1 友元类的作用友元类可以访问外部类的私有和保护成员即是友元类中的所有成员函数都是外部类的友元函数都可以访问外部类的私有和保护成员4.2.2 友元类没有双向性友元类是外部类的朋友可以访问外部类的私有和保护成员但是如果友元类中没有写外部类是它的朋友那么外部类不能访问友元类的私有和保护成员。类比就是你是我的朋友你可以来我家玩但是可能你可能没有把我当成朋友可能不让我去你家玩。4.2.3 友元类没有传递性A是B的友元类B是C的友元类不可以说A是C的友元。4.2.4 友元类的问题如果过多使用友元类会导致耦合性太强可能我这里用了你的成员你这里用了我的成员导致我改一个类的时候很有可能另一个类使用了我改的这个部分导致还需要再改这个类才能保证运行正确。当然同时也会导致封装性被破坏因为友元类不就是可以访问其他类的私有和保护成员吗过多使用导致访问限定符用处减少封装性被破坏。5 内部类#includeiostreamusingnamespacestd;classA{private:staticint_k;int_h1;public:classB// B默认就是A的友元{public:voidfoo(constAa){cout_kendl;//OKcouta._hendl;//OK}int_b1;};};intA::_k1;intmain(){coutsizeof(A)endl;A::B b;A aa;b.foo(aa);return0;}5.1 内部类的特点在计算外部类的大小时是不会加上内部类的大小的因为内部类是独立的类受到的限制就是实例化内部类对象时会受到外部类类域的限制如A::B b;同时内部类也是受到内部类访问限定符的限制的。5.2 内部和外部类的关系内部类默认是外部类的友元 但是外部类默认不是内部类的友元。友元单向5.3 内部类的用处内部类也是一种封装如果A类和B类联系紧密A类实现出来主要是给B类使用的那么设计成内部类是比较合适的并且如果不想内部类被外部使用也可以用访问限定符来限制。6 匿名对象#includeiostreamusingnamespacestd;classA{public:A(inta0):_a(a){coutA(int a)endl;}~A(){cout~A()endl;}private:int_a;};classSolution{public:intSum_Solution(10){//...return1;}};intmain(){A aa1;//A aa1();A();A(1);Aaa2(2);Solution sol;sol.Sum_Solution(10);Solution().Sum_Solution(10);return0;}6.1 匿名对象和有名对象有名对象就是A aa1;,匿名对象就是A()有必要说明一点有名对象不可以A aa1();因为会和函数声明产生歧义如void func()匿名对象可以加上括号因为不会产生歧义。6.2 匿名对象的作用匿名对象的作用其实就是让使用更加简单了。Solution sol;sol.Sum_Solution(10);Solution().Sum_Solution(10);本来要写两行的现在只用写一行了6.3 匿名对象和临时对象匿名对象是临时对象的一种生命周期在这一行所以临时使用一下变量就可以用匿名对象。7 对象拷贝时的编译器优化#includeiostreamusingnamespacestd;classA{public:A(inta0):_a1(a){coutA(int a)endl;}A(constAaa):_a1(aa._a1){coutA(const A aa)endl;}Aoperator(constAaa){coutA operator(const A aa)endl;if(this!aa){_a1aa._a1;}return*this;}~A(){cout~A()endl;}private:int_a11;};voidf1(A aa){}Af2(){A aa;returnaa;}intmain(){A aa1;f1(aa1);coutendl;f1(1);f1(A(2));coutendl;cout***********************************************endl;f2();coutendl;A aa2f2();coutendl;aa1f2();coutendl;return0;}7.1 两次连续构造7.1.1 正常优化A aa1; f1(aa1);先构造再拷贝构造由于这里是在两行的所以正常优化和激进优化都没有将这个优化掉。但是不排除特别激进的编译器会优化掉因为后面没有地方再使用aa1可能编译器会依据这个来优化f1(1);先1隐式类型转换为临时对象构造临时对象再拷贝构造给aa连续构造拷贝构造编译器之间优化为1构造aa。f1(A(2));先构造匿名对象匿名对象再拷贝构造aa优化为2构造aa。7.1.2激进优化f2();aa2先构造再传值返回aa2即aa2拷贝构造临时对象其实这里不属于连续的构造加拷贝构造因为是两行正常优化编译器是不优化的但是激进编译器还是会优化为构造即不构造aa了直接构造临时对象激进编译器就算你在中途改变了值也是可以优化的是比较激进的但是结果还是正确的。Af2(){A aa;aa;//如果重载了后置returnaa;}7.2 三次连续构造A aa2 f2();不优化是先构造aa再拷贝构造临时对象再拷贝构造aa2正常优化是构造aa再拷贝构造aa2激进优化是直接构造aa2。aa1 f2();不优化就是构造拷贝构造加上赋值重载正常优化就是不优化的情况激进优化是构造加赋值重载直接构造临时对象了赋值重载不算构造的一种所以编译器没有优化。

相关新闻

2026/9/1 6:16:04

用高德API批量把地址转经纬度,门店打点不再愁

简介:面向需要批量地理编码的Python开发者,这一源码包借助高德地图API,把Excel地址列表批量转换为经纬度,解决手动逐条查询效率低、易出错的问题。压缩包共9个文件,以6个Python脚本为主,分别承担高德地理编…

2026/9/1 6:16:04

鸿蒙原生医院陪诊系统开发实战:从需求到关键实现

简介:基于 HarmonyOS SDK 6.0.0 开发的医院陪诊系统轻应用源码包,采用 Stage 模型与 ArkTS 语言编写,面向移动应用开发初学者以及希望快速上手鸿蒙生态的开发者,用于学习注册、登录、病情选择、陪诊确认等纯文字交互流程&#xff…

2026/9/1 6:16:04

微信误删好友不用慌:wxid转二维码一键找回的完整技术方案

简介:面向微信好友误删找回与联系人二维码生成需求,这份轻量工具包提供了基于微信ID的本地网页解决方案,压缩包整体仅10KB,共包含4个文件。核心为一个HTML交互页面与一个JavaScript二维码生成库,另附Markdown说明文档和…

2026/9/1 6:26:04

Django登录页美化指南:用CSS打造炫酷毛玻璃登录界面

简介:炫酷登录界面双版本源码包(HTML版 Django版),面向Web前端及Python Web初学者,帮助解决登录页交互单一、视觉平淡的问题。HTML版通过CSS Grid划分左右区域,使用纯CSS绘制4个动画角色,并借助…

2026/9/1 6:26:04

中望CAD免费下载安装教程

中望CAD免费下载安装:国产CAD,兼容AutoCAD图纸 为什么选中望CAD 中望CAD(ZWCAD)是广州中望龙腾软件(ZWSOFT,科创板上市企业)推出的国产自主内核 CAD 制图软件。它在 DWG 图纸兼容性、操作界面、…

2026/9/1 6:26:04

Oracle 19c RU补丁前必做:OPatch升级实战与避坑指南

简介:面向Oracle 19c数据库在Linux环境下的运维需求,此资源是官方OPatch补丁应用工具包,编号p6880880-230000,适用于DBA完成补丁安装、卸载与清单验证等日常维护工作。压缩包共495个文件,体积121.72MB,以ja…

2026/9/1 6:26:04

YOLO 3D打印缺陷检测:从数据集构建到产线部署的完整实践

简介:面向深度学习与机器视觉方向的开发者、学生及研究人员,YOLO 3D打印缺陷检测数据集可作为训练YOLO系列模型进行3D打印表面缺陷识别的直接素材。数据标注采用YOLO txt格式,并已按训练集、验证集和测试集划分,能显著减少数据预处…

2026/9/1 6:26:04

欧拉视频放大EVM原理与PyEVM实现:从微小变化到可见视觉信号

简介:PyEVM是欧拉视频放大率(EVM)算法的Python实现,面向计算机视觉研究者、图像处理学习者及生物医学可视化爱好者,用于揭示普通视频中人眼难以察觉的时序变化,例如面部血流充填、微小运动等。核心EVM.py通…

2026/9/1 6:21:04

ReWEIGH技术:大视觉语言模型幻觉问题的Token级校准方案

这次我们来看一个专门解决大视觉语言模型幻觉问题的技术方案:ReWEIGH。这个项目不是新的模型,而是一种校准方法,目标是让模型在回答问题时,更准确地“看到”并“相信”图像中的证据,从而减少胡说八道。大视觉语言模型&…

2026/8/31 1:05:20

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/8/31 2:14:20

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/8/31 1:41:28

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

2026/9/1 0:00:42

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行&#xff0c;Type-C接口算是典型的“看着简单&#xff0c;做起来全坑”的东西。光引脚就24个&#xff0c;高低速信号、电源、控制线全部塞在一个小小的连接器里&#xff0c;如果PCB布局不做规划&#xff0c;打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/1 0:00:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/1 0:00:42

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…