【C++】类与对象—— 初始化列表 、static 静态成员、

在这里插入图片描述

类与对象

  • 1 再谈构造函数
    • 1.1 构造函数体赋值
    • 1.2 初始化列表
      • 语法:
      • 建议:
      • 初始化顺序:
      • 注意:
    • 1.3 explicit关键字
  • 2 static 静态成员
    • 2.1 概念
    • 2.2 声明成员变量
    • 2.3 使用类的静态成员
    • 2.4 定义静态成员
    • 总结
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 再谈构造函数

1.1 构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值,以我们之前实现的Date类对象为例。

class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};

虽然上述构造函数调用的时候,对象中成员变量都有一个初始值了,但是不能将其成为对象中成员变量的初始化,构造函数中语句只能将其成为赋初值,不能叫做初始化。因为初始化只能初始化一次,而构造函数可以多次赋值。进而我们有了初始化列表的概念。

1.2 初始化列表

语法:

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。

class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){ }private:int _year;int _month;int _day;
};

建议:

有时我们可以忽略数据成员初始化的和赋值之间的差异,但并非总是这样。
如果成员是const 或 引用变量的话,必须将其初始化。类似的如果存在自定义类型并且该类不存在构造函数时,也必须将其初始化。例如:

class A {
private:int a;
};
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}private:const int _year;int& _month;int _day;A a;
};
int main(){const Date a1(2024,2,24);return 0;
}

来看看报错:
在这里插入图片描述
显然我们需要初始化来帮助我们解决这些问题。
在很多类中初始化和赋值的区别事关底层效率的问题:前者直接初始化数据成员,后者则先初始化再赋值。除了效率问题外更重要的是,一些数据成员必须初始化。所以一般建议养成使用初始化列表的习惯,这样可以避免某些意想不到的编译错误,特别是遇到类包含构造函数初始值的成员时。

初始化顺序:

显然在构造函数中每个成员只能出现一次。否则给同一个成员赋两个不同初始值有什么意义呢?
需要注意的是初始化列表不限定初始化的执行顺序,因为成员初始化的顺序与他们在类出现顺序一致,第一个成员先初始化,然后第二个,以此类推,因此构造函数初始化列表的前后位置并不影响实际的初始化顺序。
但是下面这个例子不同:

class A
{
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private:int _a2;int _a1;
};
int main() {A aa(1);aa.Print();
}

我们想要两个输出 1 1 ,但是程序实际输出了:
在这里插入图片描述
这就是因为初始化顺序的问题了,因为成员_a2在_a1前,所以先对_a2初始化,就造成了随机值。

注意:

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能一次)
  2. 类中包括以下成员,必须在初始化列表进行初始化 :
    引用成员变量
    const成员变量
    自定义类型成员(并且该类没有默认构造函数时)
  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化
  4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。

1.3 explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

class Date
{
public:
// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译explicit Date(int year):_year(year){}
private:int _year;int _month;int _day;
};
void Test()
{Date d1(2022);// 用一个整形变量给日期类型对象赋值// 实际编译器背后会用2023构造一个无名对象,//最后用无名对象给d1对象进行赋值}
 class Date
{
public:
// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,
//没有使用explicit修饰,具有类型转换作用
// explicit修饰构造函数,禁止类型转换explicit Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};
void Test()
{Date d1(2022);
// 用一个整形变量给日期类型对象赋值
// 实际编译器背后会用2023构造一个无名对象,
//最后用无名对象给d1对象进行赋值d1 = 2023;
// 将 1 屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,
//禁止了单参构造函数类型转换的作用
}

由于上述代码可读性不是很好,所以一般单参数的类构造都要使用explicit修饰。

2 static 静态成员

有时候类需要一些成员与类本身直接相关,而不是与类的各个对象保持联系。
例如,一个银行账户类对象可能需要一个数据成员来表示当前基准利率。在此例中,我们希望利率与类关联,而不是与类的每个对象关联。从实现效率的角度来看,没必要每个对象都储存利率信息。而且更加重要的是,一旦利率浮动,我们希望所有对象都可以使用新值。所以我们引入静态成员的概念。

2.1 概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数。静态成员变量一定要在类外进行初始化

2.2 声明成员变量

我们通过在成员的声明之前加入关键字 static 就可以创建,和其他成员一样,静态成员也是可以被 public 或 private的。静态成员变量的类型可以是常量,引用,指针,类类型等。
并且,静态成员函数也不与任何对象绑定在一起,他们不包含this指针。作为结果,静态成员函数不能声明成const 的而且我们也不能在static 函数体内使用this指针。这一限制及适用于this的显式使用,也对调用非静态成员的隐式使用有效。

2.3 使用类的静态成员

使用时我们通过作用域运算符直接访问静态成员。
虽然静态成员不属于类的某个对象,但是我们依然可以使用类的对象、引用、或者指针来访问静态成员。如下:

class Date
{
public:Date(int year, int month, int day):_year(year),_month(month),_day(day){ }
static void count();
private:int _year;int _month;int _day;
};
void count(){
}int main(){Date d1;Date* d2 = &d1; d2->count();d1.count();return 0;
}

2.4 定义静态成员

和其他成员函数一样,我们既可以在类内部也可以在外部定义。当在类外定义时,不需要重复写 static 关键字,该关键字只出现在类内部的声明语句。
和类的所有成员一样,当我们指向类外部的静态成员时,必须指明成员所属的类名。static 关键字则只出现在类内部的声明语句中
要确保对象只定义一次,最好的办法就是把静态成员的定义与其他非内联函数的定义于同一个文件中。

总结

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用 类名 :: 静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/263414.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C/C++的内存管理(1)

内存管理 C与C的内存分布C语言中动态内存管理方式回顾C内存管理的方式 C与C的内存分布 我们学习C语言时就知道&#xff0c;储存不同的变量计算机会相应分配不同区块的内存。那为什么要把内存化为不同的区域呢&#xff1f;实质上是为了方便管理 下面我们来看看下面一道例题&…

Camunda7.18流程引擎启动出现Table ‘camunda_platform_docker.ACT_GE_PROPERTY‘的解决方案

文章目录 1、问题描述2、原因分析3、解决方案3.1、方案一&#xff1a;降低mysql版本3.2、方案二&#xff1a;增加nullCatalogMeansCurrent参数&#xff08;推荐&#xff09; 4、总结 1、问题描述 需要在docker中&#xff0c;部署Camunda流程引擎。通过启动脚本camunda-platfor…

Linux内核源码安装

文章目录 前言查看内核源码包安装内核源码编译内核源码最后 前言 我是醉墨居士&#xff0c;我们安装一下Linux内核源码&#xff0c;方便我们学习Linux内核 也方便我们进行eBPF开发时查看Linux内核的一些信息 查看内核源码包 apt-cache search linux-source安装内核源码 因为…

Unity实现帧序列

一、目的 1.想实现序列帧效果 自己使用Animation一直无法实现动画播放效果 二、参考 1. Unity序列帧动画——Sprite图片集制作UI动画_unity 序列帧动画图集-CSDN博客 结果&#xff1a;很好用&#xff0c;能实现效果 三、实操 新建Image&#xff0c;增加Animator组件&#x…

mac苹果电脑系统最好用的清理软件CleanMyMac2024功能介绍及如何激活解锁许可证

CleanMyMac X的界面设计简洁大气&#xff0c;为用户提供了直观且易于操作的使用体验。 布局清晰&#xff1a;界面布局非常明朗&#xff0c;左侧是功能栏&#xff0c;右侧则是信息界面。这种布局方式使得用户能够迅速找到所需的功能选项&#xff0c;提高了操作效率。色彩搭配&a…

Guava处理异常

guava由Google开发&#xff0c;它提供了大量的核心Java库&#xff0c;例如&#xff1a;集合、缓存、原生类型支持、并发库、通用注解、字符串处理和I/O操作等。 异常处理 传统的Java异常处理通常包括try-catch-finally块和throws关键字。 遇到FileNotFoundException或IOExce…

黑马JavaWeb开发跟学(一)Web前端开发HTML、CSS基础

黑马JavaWeb开发一.Web前端开发HTML、CSS基础 引子、Web开发介绍传统路线本课程全新路线本课程适用人群课程收获一、什么是web开发二、网站的工作流程三、网站的开发模式四、网站的开发技术 前端开发基础一、前端开发二、HTML & CSS2.1 HTML快速入门2.1.1 操作第一步第二步…

STM32F10X(Cortex-M3)系统定时器寄存器笔记和系统定时器精准延时函数

Cortex-M3系统定时器寄存器笔记和系统定时器精准延时函数 简介系统定时器寄存器STK_CTRLSTK_LOADSTK_VALSTK_CALIB STM32F10X(Cortex-M3)精准延时函数 简介 在STM32F10X(Cortex-M3)除了通用定时器和看门狗定时器外&#xff0c;还有一个系统定时器(SysTick) 拿STM32F103C8T6来说…

SpringBootWeb请求响应

SpringBootWeb请求响应 这里写目录标题 SpringBootWeb请求响应前言1. 请求1.1 Postman1.1.1 介绍1.1.2 安装 1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 …

计算机网络-局域网

文章目录 局域网局域网拓扑结构以太网以太网传输介质以太网时隙提高传统以太网带宽的途径以太网帧格式 局域网协议IEEE 802参考模型IEEE802.2协议LLC帧格式及其控制字段LLC提供的三种服务 IEEE 802.3协议IEEE 802.4协议IEEE 802.5协议 高速局域网100M以太网千兆以太网万兆以太网…

SQL-Labs46关order by注入姿势

君衍. 四十六关 ORDER BY数字型注入1、源码分析2、rand()盲注3、if语句盲注4、时间盲注5、报错注入6、Limit注入7、盲注脚本 四十六关 ORDER BY数字型注入 请求方式注入类型拼接方式GET报错、布尔盲注、延时盲注ORDER BY $id 我们直接可以从界面中得知传参的参数为SORT&#x…

源代码管理——码云Gitee

目录 Git安装 Gitee配置SSH 源代码管理常规操作 1.idea配置git 2.常规操作 Git安装 安装Git是进行源代码管理的基本步骤之一。以下是在本地安装Git的通用步骤&#xff0c;适用于Windows系统&#xff1a; 下载Git安装程序: 访问Git官网的下载页面&#xff1a;Git官网下载地…

数据存储-文件存储

一、CSV文件存储 csv是python的标准库 列表数据写入csv文件 import csvheader [班级, 姓名, 性别, 手机号, QQ] # 二维数组 rows [[学习一班, 大娃, 男, a130111111122, 987456123],[学习二班, 二娃, 女, a130111111123, 987456155],[学习三班, 三娃, 男, a130111111124, …

【大数据】Flink 内存管理(二):JobManager 内存分配(含实际计算案例)

《Flink 内存管理》系列&#xff08;已完结&#xff09;&#xff0c;共包含以下 4 篇文章&#xff1a; Flink 内存管理&#xff08;一&#xff09;&#xff1a;设置 Flink 进程内存Flink 内存管理&#xff08;二&#xff09;&#xff1a;JobManager 内存分配&#xff08;含实际…

谷歌收购域名花费了100万美元的确让大家眼红

谷歌斥资100万美元购买了该域名。 卖个好价钱确实让大家眼红&#xff0c;但能不能卖到高价就是另一回事了。 首先&#xff0c;据统计&#xff0c;截至2008年底&#xff0c;我国域名总数达到1680万多个&#xff0c;可用的域名资源几乎无法统计&#xff0c;因为英文的组合太多了…

基于SpringBoot的家教管理系统

基于SpringBootVue的家教管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 前台主页 家教 个人中心 管理员界面 摘要 本文介绍了基于SpringBoot框架开发的家…

SpringMVC 学习(二)之第一个 SpringMVC 案例

目录 1 通过 Maven 创建一个 JavaWeb 工程 2 配置 web.xml 文件 3 创建 SpringMVC 配置文件 spring-mvc.xml 4 创建控制器 HelloController 5 创建视图 index.jsp 和 success.jsp 6 运行过程 7 参考文档 1 通过 Maven 创建一个 JavaWeb 工程 可以参考以下博文&#x…

【鸿蒙开发】第十四章 Stage模型应用组件-任务Mission

1 任务(Mission)管理场景 任务&#xff08;Mission&#xff09;管理相关的基本概念如下&#xff1a; AbilityRecord&#xff1a;系统服务侧管理一个UIAbility实例的最小单元&#xff0c;对应一个应用侧的UIAbility组件实例。系统服务侧管理UIAbility实例数量上限为512个。 Mi…

5.1 Ajax数据爬取之初介绍

目录 1. Ajax 数据介绍 2. Ajax 分析 2.1 Ajax 例子 2.2 Ajax 分析方法 &#xff08;1&#xff09;在网页页面右键&#xff0c;检查 &#xff08;2&#xff09;找到network&#xff0c;ctrl R刷新 &#xff08;3&#xff09;找 Ajax 数据包 &#xff08;4&#xff09;…

力扣用例题:2的幂

此题的解题方法在于根据用例调整代码 bool isPowerOfTwo(int n) {if(n1){return true;}if(n<0){return false;}while(n>2){if(n%21){return false;}nn/2; }if(n1){return false;}return true;}