C++类和对象(四)—— 初始化列表、类型转换、static、友元、内部类、匿名对象与编译器优化

发布时间:2026/10/18 18:07:28

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/10/13 8:46:24

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

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

2026/10/13 19:30:57

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

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

2026/10/17 5:53:44

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

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

2026/10/18 18:03:36

政务数据分类分级落地难?低代码配置与业务赋能实践指南

这两年做政务数据相关项目的人,基本都绕不开“分类分级”这四个字。标准文件翻来覆去读了好几遍,方案PPT也写了几十页,但一落到实际环境里,经常是台账做了一本又一本,系统里该有的策略一条没配上。真正的问题不是大家不…

2026/10/18 18:03:36

形变场形式转换实战:DDF、B样条与速度场互转及避坑指南

做配准项目时间长了,你会发现一个规律:算法输出给你的,不一定是下游真正需要的。上周我处理一个跨模态配准任务,跑完变形模型,拿到的是一套B样条控制点和速度场,可下游要用来做标签传播,需要的是…

2026/10/18 18:03:36

YOLO结合SubspaceAD:一张良品图检出所有未知缺陷

YOLO SubspaceAD:一张良品图,检出所有未知缺陷在工业质检这个圈子里摸爬滚打了几年,我越来越觉得传统的视觉检测方案到了一个瓶颈:已知缺陷能查,但新出现的缺陷形态往往要等客户投诉之后才后知后觉。这次我想聊聊一套…

2026/10/18 18:03:36

机器学习分类任务全流程指南:从数据准备到模型评估

拿到“第五章:如何处理分类任务(预习)”这个标题,我第一反应是:这不就是大多数人在机器学习入门阶段都会卡住的那一章吗?前面还在学回归、学损失函数、学梯度下降,突然进入分类任务,…

2026/10/18 18:03:36

C#彻底删除PDF数字签名:字段、外观与残留清理全攻略

收到需求“用 C# 删除 PDF 里的数字签名”,大部分人以为这是件小事,打开文件、删个字段、保存,三行代码搞定。实际上我第一次接到类似需求就栽了跟头:用 RemoveField 删掉字段后,页面上的签名图片还赖着不走&#xff1…

2026/10/18 17:58:36

国产AI加速卡上的垂域大模型训练:从硬件选型到微调实战

过去一年我大部分时间都泡在国产AI加速卡的训练集群上,折腾的不是那种演示级别的玩具模型,而是真正要落地到具体行业里的垂域大模型。垂直行业的模型训练和微调,跟互联网那种亿万级通用数据训练完全是两码事:数据量没那么多&#…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

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

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

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