类和对象(4)

article/2025/8/1 17:10:50

(本文是《类和对象》的收尾)

一.构造函数初始化的逻辑

1.构造函数的初始化列表使用说明                            初始化列表是以冒号开头、逗号分隔成员变量的初始化方式,格式为: 构造函数() : 成员1(初始值), 成员2(表达式) { ... } 。

如下图,以Date为例

 ①. 初始化列表格式

- 构造函数名(参数列表) : 成员变量1(初始值1), 成员变量2(初始值2), ...

- 在这段代码中, Date(int& ret, int year = 1, int month = 1, int day = 1) 是构造函数,冒号 : 后面是初始化列表。

- 例如 :_ret(ret) , _ret 是类 Date 中的成员变量(引用类型),括号里的 ret 是构造函数传入的参数,通过这种方式用传入参数对成员变量进行初始化 。

- 又如 ,_year(year)  , _year 是类的成员变量,用构造函数传入的 year 参数对其初始化。

②. 特殊成员的初始化

- 这里的 _ret 是引用成员变量,引用成员变量必须在初始化列表中初始化,这是符合初始化列表使用规则的。因为引用必须在定义时初始化,不能在构造函数体内再赋值。

 

2.核心规则与注意事项                                                       - 使用限制:

- 引用成员、 const 成员、无默认构造函数的类类型成员,必须通过初始化列表初始化,否则编译报错。

- 每个成员变量在初始化列表中只能出现一次,其本质是成员变量的定义初始化位置。

- C++11 缺省值机制:

- 成员变量可在声明时指定缺省值,若初始化列表未显式初始化该成员,则自动使用此缺省值。

- 性能与初始化逻辑:

- 建议优先使用初始化列表:未在列表中显式初始化的成员,仍会通过初始化列表完成初始化:

- 内置类型:若声明时无缺省值,是否初始化由编译器决定(C++未规定);

- 自定义类型:调用其默认构造函数,若无则编译报错。

- 初始化顺序由成员在类中声明的顺序决定,与初始化列表中的顺序无关,建议两者保持一致以避免混淆。

 

 1.  Time 类                                                                                   初始化: Time 类有构造函数 Time(int hour)  ,通过成员初始化列表 : _hour**our)  ,将传入的参数 hour 赋给成员变量 _hour  ,在构造对象时就确定了 _hour 的值,同时构造函数内输出 "Time()"  ,提示构造函数执行。

 

2.  Date 类                                                                              初始化: Date 类的构造函数 Date()  ,利用初始化列表 : _month(2)  ,把成员变量 _month 初始化为 2  ,并在构造函数中输出 "Date()"  。

   缺省值:类中 _year 和 _month 等成员变量声明时给了缺省值(如 int _year = 1;  ),这不是直接初始化。若初始化列表未对其显式初始化,就会按缺省值初始化。这里 _month 在初始化列表已显式初始化, _year 未在初始化列表处理,按缺省值 1 初始化 , _day 没缺省值也没在初始化列表初始化,值不确定(输出为 0  )。

 

总结                                                                                        ①每个构造函数隐含初始化列表,所有成员变量均通过此列表完成初始化;

②显式使用初始化列表可更高效、准确地控制成员初始化逻辑,尤其适用于有特殊初始化要求的成员(如引用、 const 、无默认构造的类类型)。

 

 

 看一段特殊的代码:

 以上代码出现这种结果是因为成员变量初始化顺序是按声明顺序。代码里 _a2 声明在前,初始化 _a2(_a1)  时 _a1 还未初始化 , _a2 未按缺省值 2 初始化,成了未初始化的随机值(这里是 -858993460  ) ,之后 _a1 按构造函数初始化列表被初始化为 1  ,所以输出 1 -858993460  。 应调整成员变量声明顺序,让 _a1 在前,或合理设置初始化逻辑来避免此类问题。

 

二.C++类型转换

1.类型转换

- C++支持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数
- 构造函数前面加explicit就不再支持隐式类型转换。
- 类类型的对象之间也可以隐式转换,需要相应的构造函数支持

 

2.类型转换实例

1.单参数类型转换

 在以上C++ 代码 Date d1 = 2025;  中,存在隐式类型转换机制。 Date  类定义了单参数构造函数 Date(int year)  ,当执行该语句时,编译器会自动调用此构造函数,把 int  类型的 2025  转换为 Date  类型对象 d1  。

 

2.多参数类型转换

   以上代码                                                                                   1. 构造函数实现多参数转换: Date  类定义了多参数构造函数  Date(int year, int month, int day)  ,当执行  Date d1 = { 2025, 5, 12 };  时,编译器会调用此构造函数。它将三个  int  类型的实参  2025  、 5  、 12  分别转换并赋值给类的私有成员变量  _year  、 _month  、 _day  ,完成从  int  类型数据到  Date  类对象成员变量的类型转换与初始化。

2. 列表初始化与转换:这里使用了花括号初始化列表的形式  Date d1 = { 2025, 5, 12 };  ,这是 C++11 引入的统一初始化语法。对于类类型对象,只要存在合适的构造函数(此处的多参数构造函数),就能通过这种方式将对应类型(这里是  int  类型)的初始化列表中的值,按照顺序转换并传递给构造函数,进而初始化对象的成员变量。

3.类类型和类类型之间的转换

 以上代码:

1. 类  Date  构造函数用于类型转换: Date  类有构造函数  Date(const A& a)  ,它以类  A  的常引用为参数。当执行  Date d1 = aa;  时,会调用该构造函数,将类  A  类型对象  aa  转换为  Date  类型对象  d1  ,通过调用  a.get()  获取值来初始化  Date  类的  _year  成员变量。

2. 隐式类类型转换:此构造函数使得从  A  类对象到  Date  类对象的隐式转换成为可能。只要存在这样适配的构造函数,编译器就能自动进行这种类型转换操作 ,但也可能带来意外转换问题,必要时可加  explicit  修饰构造函数阻止隐式转换。

 

4.C语言和C++类型转换对比

 

3.static修饰的类成员

1.static成员

静态成员变量                                                                       - 被  static  修饰的成员变量即静态成员变量,它必须在类外初始化。这是因为静态成员变量为所有类对象共享,不隶属于单个对象,存储于静态区 。

 

静态成员函数                                                                        - 由  static  修饰的成员函数是静态成员函数,其没有  this  指针。由于缺少  this  指针,静态成员函数只能访问其他静态成员,无法访问非静态成员。

- 与之相对,非静态成员函数可自由访问静态成员变量与静态成员函数。

 

静态成员访问                                                                       - 突破类作用域即可访问静态成员,可通过“类名::静态成员” 或 “对象.静态成员” 方式进行,且静态成员同样受  public 、 protected 、 private  访问限定符约束。

- 需注意,静态成员变量不能在声明处用缺省值初始化,因其不依赖特定对象,不遵循构造函数初始化列表规则。

2.static使用实例

 以上代码中                                                                        静态成员变量  _Count 
 1. 声明与初始化:在类  A  中用  static  修饰声明了  int _Count  ,这是静态成员变量,它为所有  A  类对象共享。在类外进行了初始化  int A::_Count = 0;  ,符合静态成员变量需在类外初始化的规则。
2. 使用与计数逻辑:在类的构造函数  A()  中,执行  _Count++  ,每创建一个对象, _Count  就自增 1 ;拷贝构造函数  A(const A& a)  中, ++_Count  ,每次执行拷贝构造也使  _Count  增加 1 ;析构函数  ~A()  里, --_Count  ,对象销毁时  _Count  自减 1 。最终  aal.Print()  输出的  3  ,是因为经过对象创建、拷贝构造等操作后, _Count  累计增加到了  3   。
 
静态成员变量的特性体现
 1. 共享性: _Count  不属于任何单个  A  类对象,无论创建多少个  A  类对象,都共享这一个  _Count  变量,用于记录对象相关的数量变化(此处类似对象创建和拷贝的计数 )。
2. 访问规则:尽管  _Count  是  private  权限,但在类内成员函数(如构造、析构、拷贝构造、 Print  函数 )中可以正常访问和操作,体现了静态成员同样受访问限定符约束的特性。

3.练习题static的使用

计算1+2+3+.....+n

 这是一段 C++ 代码,定义了 Solution  类,其中定义了内部类Sum  类。 Sum  类的构造函数通过操作静态成员变量 _ret  和 _i  来实现累加逻辑。 Solution  类的 Sum_Solution  函数创建 Sum  类对象数组,触发构造函数执行,最终返回累加结果。巧妙运用类的嵌套和静态成员,展现了独特的编程思路与数据处理方式 。

四.友元

1.友元

友元概述

友元是 C++ 中突破类访问限定符封装的机制,分为友元函数和友元类 。在函数声明或类声明前加  friend  关键字,并将其声明置于某个类定义内部,即可确立友元关系。

 

友元函数特性

- 访问权限:外部友元函数能够访问类的私有和保护成员。需注意,友元函数并非类的成员函数,只是借助声明获得特殊访问权。

- 声明灵活性:友元函数在类定义中的声明位置不受访问限定符约束,可在任意位置声明。而且,一个函数可以同时成为多个类的友元函数 。

 

友元类特性

- 成员函数权限:友元类中的所有成员函数,皆可作为另一个类的友元函数,进而访问该类的私有和保护成员。

- 关系属性:友元类关系具有单向性,无交换性 ,比如 A 类是 B 类的友元,B 类不一定是 A 类的友元;同时也不具备传递性,若 A 是 B 的友元,B 是 C 的友元,A 并非自动成为 C 的友元。

 

应用考量

友元在某些场景能带来便利,比如方便实现特定功能的跨类操作。但它会增加类之间的耦合度,破坏类的封装性,因此在实际编程中应谨慎、适度使用。

 

五.内部类

内部类定义

 若一个类定义于另一个类的内部,此为内部类 。内部类是独立的类,与全局定义的类相比,仅受外部类的类域及访问限定符约束。外部类对象并不包含内部类对象。

 

友元关系特性

 内部类默认作为外部类的友元类 ,这赋予内部类可访问外部类私有和保护成员的权限,便于二者间交互协作。

 

封装应用场景

 内部类也是一种封装手段。当 A 类与 B 类联系紧密,且 A 类主要为 B 类所用时,可将 A 类设计为 B 类的内部类。若置于  private  或  protected  区域,A 类就成为 B 类专属内部类,在类外其他地方无法使用,增强了代码的安全性与内聚性 。

 

友元与内部类对比

 

 


http://www.hkcw.cn/article/ANymALfVKJ.shtml

相关文章

大规模真实场景 WiFi 感知基准数据集

一段话总结 本文提出CSI-Bench,首个大规模真实场景WiFi感知基准数据集,覆盖26个室内环境、35名用户、16种商用设备,包含461小时有效数据,支持跌倒检测、呼吸监测、定位、运动源识别等单任务及用户身份、活动、 proximity联合标注的多任务学习。通过标准化评估协议和基线模…

io流2——字节输入流,文件拷贝

!基本代码演示: 读取: 到程序中不是a,而是a的asicc码对应的数字 继续读读到最后: 不想看到数字,还想看abcde: 再继续读: 如果读不到了,就会返回-1 细节 细节一 细节2 字节输入流循环读取 …

沈白高铁开始最后测试 东北东部快速铁路通道进入联调联试

6月1日,首趟执行联调联试任务的综合巡检车从沈阳北站出发。沈白高铁开通运营后,辽宁将实现“市市通高铁”,对完善辽宁综合立体交通网络布局具有重要意义。这条高铁线路也将结束吉林省通化市、白山市不通高铁的历史,极大带动沿线旅游资源的开发。沈白高铁正线起自沈阳北站,…

山东友道化工厂爆炸前后 居民生活受冲击

山东友道化学有限公司发生爆炸事故,造成严重后果。事故发生时,距离公司1.7公里外的仁和街居民家窗户被震碎,范丽家超市的顶棚掉落,导致她头部受伤。诊所医生在当天下午处理了20多人的伤口,未收取费用。范丽的儿子从外地赶回家,将她送往医院治疗。高密仁和化工产业园内的友…

景区撒1千斤蚬子:让赶海游客有收获,吸引上万游客参与

近两日,多名网友分享了在辽宁省大连市夏家河子海滨浴场偶遇工作人员开着铲车、三轮车给游客撒蚬子赶海的场景。6月1日,景区回应称,在沙滩撒蚬子是为了让赶海的游客都能挖到东西。这两天,景区每天需要撒约1000斤的蚬子。此外,还有巴掌大的鲍鱼和海螺,如果游客捡到可以兑换…

萨巴伦卡2-0阿尼西莫娃 将战郑钦文 连胜挺进八强

在2025年法网女单1/8决赛中,头号种子萨巴伦卡以7-5和6-3的比分击败阿尼西莫娃,顺利晋级八强。这是萨巴伦卡连续第三年进入法网八强,并且她在最近参加的十个大满贯赛事中都至少闯入了八强,总计第十二次。接下来,萨巴伦卡将迎战中国选手郑钦文。这将是两人之间的第八次对决。…

关于神经网络中的激活函数

这篇博客主要介绍一下神经网络中的激活函数以及为什么要存在激活函数。 首先,我先做一个简单的类比:激活函数的作用就像给神经网络里的 “数字信号” 加了一个 “智能阀门”,让机器能学会像人类一样思考复杂问题。 没有激活i函数的神经网络…

开始使用 Elastic AI Assistant for Observability 和 Amazon Bedrock

作者:来自 Elastic Jonathan Simon 及 Udayasimha Theepireddy (Uday) 按照以下分步流程开始使用 Elastic AI Assistant for Observability 和 Amazon Bedrock。 如果你想使得下面的操作适用于 DeepSeek R1,那么你可以更进一步阅读文章 “使用 Ollama 和…

[平台运营] CSDN评论折叠机制对内容引流的影响与实践反思

[网页链接]在内容创作和知识分享过程中,很多技术博主会选择在 CSDN 这样的专业平台发布文章、经验总结或教程,并希望通过评论、互动的方式进一步引流到自己的其他优质内容(例如视频课程、开源项目等)。 但最近我在实操中遇到了一些有趣的现象,想在这里做个记录和分享,供有…

51单片机基础部分——LED

前言 之前更新过了蓝桥杯单片机的相关部分,那也是一款51单片机,主控芯片是STC15,现在我们要使用的是AT89C52,操作基于普中的51开发板进行开发,入门款的芯片,属于比较简单的,所以我们了解一下就…

js实现猜数字案例

<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body></body><script>// 猜随机数// 生成一个随机数并取整var guessNumber Math.floor(Math.random() * 100)console.log(…

[AI算法] LLM中LoRA的占用显存没有减少多少?

文章目录 Lora为什么没有减少多少显存几种Freeze的设置方式torch.no_gradrequire_gradFalseeval() Lora为什么没有减少多少显存 在使用 PEFT&#xff08;Parameter-Efficient Fine-Tuning&#xff09; 方法&#xff08;如 LoRA、IA 等&#xff09;时&#xff0c;你可能会观察到…

C++命名空间深度解析

1.命名空间的价值 在C/C中&#xff0c;变量、函数和类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;以避免命名冲突或名字污染&#xff0c;namespace…

上海工作机会:Technical Writer Senior Technical Writer - 中微半导体设备

大名鼎鼎的中微半导体招聘文档工程师了,就是那家由中国半导体产业的领军人物尹志尧领导的、全员持股的公司。如果你还不了解他,赶快Deepseek一下“尹志尧”了解。 招聘职位:Technical Writer & Senior Technical Writer 公司名称:中微半导体设备(上海)股份有限公司…

2024年12月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:最近的斐波那契数 斐波那契数列 Fn 的定义为:对 n ≥ 0 有 Fn+2 = Fn+1 + Fn,初始值为 F0 = 0 和 F1 = 1。所谓与给定的整数 N 最近的斐波那契数是指与 N 的差之绝对值最小的斐波那契数。 本题就请你为任意给定的整数 N 找出与之最…

大数据集群架构hadoop集群、Hbase集群、zookeeper、kafka、spark、flink、doris、dataease(三)

hbase集群部署 wget -c https://dlcdn.apache.org/hbase/2.5.10/hbase-2.5.10-bin.tar.gz 下载地址 在master-1操作 tar xf hbase-2.5.10-bin.tar.gz -C /data/ && mv /data/hbase-2.5.10 /data/hbase vim /etc/profile export HBASE_HOME/data/hbase export PAT…

2022—2025年:申博之路及硕士阶段总结

文章目录 1 前景概要2 打造神兵利器2.1 夺天地之精2.2 锻兵魂之形2.3 契人兵之命 3 潜心闭关修炼3.1 第一阶段&#xff1a;苦心智3.2 第二阶段&#xff1a;劳筋骨3.3 第三阶段&#xff1a;摧意志 4 突破晋级4.1 突破失败4.2 聚气凝神4.3 心魔再现4.4 新起点 5 回顾及深思 1 前景…

NetSuite Bundle - Dashboard Refresh

儿童节快乐&#xff01; 今朝发一个Bundle&#xff0c;解决一个NetSuite Dashboard的老问题。出于性能上的考虑&#xff0c;NetSuite的Dashboard中的Portlet&#xff0c;只能逐一手工刷新。有人基于浏览器做了插件&#xff0c;可以进行自动刷新。但是在我们做项目部署时&#…

简析PointNet++

简析PointNet 更好的阅读体验&#xff0c;欢迎访问 简析PointNet 获得 论文: https://arxiv.org/abs/1706.02413 TensorFlow 版本代码: https://github.com/charlesq34/pointnet2 Pytorch 版本代码: https://github.com/yanx27/Pointnet_Pointnet2_pytorch 背景 在PointNet中…

2024 CKA模拟系统制作 | Step-By-Step | 8、题目搭建-创建 Ingress

目录 ​​​​​​免费获取题库配套 CKA_v1.31_模拟系统 一、题目 二、核心考点 Ingress 资源定义 Ingress Controller 依赖 服务暴露验证 网络层次关系 三、搭建模拟环境 1.创建命名空间 2.安装ingress ingress-nginx-controller 3.创建hello.yaml并部署 四、总结 …