【C++】类和对象之初始化列表与static成员

个人主页 : zxctscl
文章封面来自:艺术家–贤海林
如有转载请先通知

文章目录

  • 1. 前言
  • 2. 再谈构造函数
    • 2.1 构造函数体赋值
    • 2.2 初始化列表
    • 2.3 explicit关键字
  • 3. static成员
    • 3.1 概念
    • 3.2 特性

1. 前言

在前面的博客中已经分享有关构造函数 【C++】构造函数和析构函数详解,这次又再一次提到构造函数,一起来看看。

2. 再谈构造函数

2.1 构造函数体赋值

在之谈到构造函数时候是在函数体里面初始化,举个例子:

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

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值

2.2 初始化列表

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

#include<iostream>
using namespace std;class Date
{
public:// 初始化列表Date(int year, int month, int day): _year(year), _month(month), _day(day){}private:int _year; int _month;int _day;};

在这里插入图片描述

在这里插入图片描述
其他的成员既可以在初始化列表,也可以在函数体。
这里_n没有办法初始化,它只能在函数体。

在这里插入图片描述
声明并没有定义,是在对象实例化的时候才整体定义。
但是有一些成员必须在定义的时候初始化。
在这里插入图片描述

如果函数体里面出现像下面_year这样的情况,该怎么办?
在这里插入图片描述
所以c++中用了初始化列表,初始化列表是每个成员变量定义初始化的位置。
在这里插入图片描述
下面的成员变量也会走初始化列表,他们也要定义,只是没有给值就是随机值,如果给了值就直接初始化。
在这里插入图片描述
在既有缺省值(不给值就用缺省值)又有初始化列表,走的是初始化列表的值。
在这里插入图片描述
先走初始化列表再走下面的赋值修改。
在这里插入图片描述
那么函数体和初始化列表哪个好用呢?
初始化列表是每个成员变量定义初始化的位置, 能用初始化列表就建议用初始化列表。
不用也会先走初始化列表。

哪些成员必须用初始化列表呢?
const,引用(引用必须在定义的时候初始化)
在这里插入图片描述

class A
{
public:A(int a = 0):_a(a){cout << "A(int a = 0)" << endl;}private:int _a;
};class Date
{
public:Date(int year, int month, int day, int& x):_year(year), _month(month), _day(day), _n(1), _ref(x){}private:// 声明int _year;int _month;int _day;const int _n;int& _ref;A _aa;
};int main()
{int x = 10;Date d1(2024, 1, 31, x);return 0;
}

在这里插入图片描述
这里会调A的默认构造函数,不传参也会调。
在这里插入图片描述

如果A没有默认构造调怎么办?
那就用初始化列表。
在这里插入图片描述

这里是显示的调构造
在这里插入图片描述

在这里插入图片描述
【注意】

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

  2. 类中包含以下成员,必须放在初始化列表位置进行初始化,不能在函数体内初始化:
    (1)引用成员变量
    (2)const成员变量
    (3)自定义类型成员(且该类没有默认构造函数时)

  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
    在这里插入图片描述
    当然混合使用也是可以的。

class A
{
public:A(int a = 0,int b=1):_a(a){cout << "A(int a = 0)" << endl;}private:int _a;
};class Date
{
public:Date(int year, int month, int day, int& x):_year(year), _month(month), _day(day), _n(1), _ref(x), _aa(1, 2)	,_p((int*)malloc(sizeof(4) * 10)){if (_p == nullptr){perror("malloc fail");}}private:// 声明int _year;int _month;int _day;const int _n;int& _ref;A _aa;int* _p;
};int main()
{// 对象实例化int x = 10;Date d1(2024, 1, 31, x);A aa(2, 3);return 0;
}

在这里插入图片描述
在这里插入图片描述

class B
{
private:// 缺省值int a = 1;int* p1 = nullptr;int* p2 = (int*)malloc(4);}int main()
{B bb;return 0;
}

初始化列表能像下面这样写,缺省值也能这样写。
在这里插入图片描述
在这里插入图片描述

class C
{
public://explicit C(int x = 0)C(int x = 0):_x(x){}private:int _x;
};class B
{
private:// 缺省值int a = 1;int* p1 = nullptr;int* p2 = (int*)malloc(4);
}int main()
{B bb;C cc1(1);C cc2 = 2;return 0;
}

这样也可以,是为什么呢?
这里是:单参数构造函数支持隐式类型的转换。
2构造一个临时对象,再拷贝构造
在这里插入图片描述
像下面那种原理一样:
在这里插入图片描述
---------------------------------------------------------------------------------------------------------------------------------
在这里插入图片描述
如果有拷贝构造会不会调用呢?
不会,2构造一个临时对象,再拷贝构造 -> 编译器优化了,同一个表达式连续步骤的构造,一般会被合二为一
---------------------------------------------------------------------------------------------------------------------------------
这个代码为什么可以?
类型转换会产生临时变量。
在这里插入图片描述
就像下面这样,临时变量具有常性。
在这里插入图片描述
---------------------------------------------------------------------------------------------------------------------------------
在这里插入图片描述
内置类型可以给缺省值,而自定义类型给个缺省值还要定义一个全局变量,很麻烦。

那么为什么下面这样可以?
到时候初始化列表就直接用2去初始化,和上面的原因一样:同一个表达式连续步骤的构造,一般会被合二为一
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

  1. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。

看看这个程序:

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();
}

这个程序输出的结果是什么呢?
A.输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值
在这里插入图片描述
这里选D,这里先走了_a2,再走的_a1。
它是按照声明的顺序进行的,内存存储的就是声明的顺序。
在这里插入图片描述
在内存先走了_a2,再走的_a1。
在这里插入图片描述

所以声明和定义的初始化列表的顺序得保持一致。

2.3 explicit关键字

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

C++11支持多参数
举个例子:

class A
{
public:A(int a1, int a2):_a1(a1),_a2(a2){}private:int _a1;int _a2;
};int main()
{A aa1 = { 1, 2 };const A& aa2 = { 1, 2 };return 0;
}

如果不想这样就加一个 explicit关键字
explicit修饰构造函数,禁止类型转换
在这里插入图片描述
虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具
有类型转换作用

用explicit修饰构造函数,将会禁止构造函数的隐式转换。

class A
{
public:A(int a1, int a2):_a1(a1), _a2(a2){}private:int _a1;int _a2;
};class B
{
private:// 缺省值int _a = 1;int* _p = (int*)malloc(4);A aa1 = { 1,2 };
};

缺省值有这些写法:
在这里插入图片描述

3. static成员

3.1 概念

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

面试题:实现一个类,计算程序中创建出了多少个类对象。
就是统计构造,构造函数调用了多少次。
得用一个全局变量

int n = 0;
class A
{
public:A(){++n;}A(const A& aa){++n;}A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();cout << n << endl;return 0;
}

但这个代码在Debug和Release结果不一样。
Release做了代码的优化。

如果把n封装到类里面去,这里加加的n可能不同,所以给一个静态的n,但静态的不能给一个缺省值,因为不是属于某一个对象,属于所有对象,属于整个类。所以它得在类外面定义。

class A
{
public:A(){++n;}A(const A& aa){++n;}private:// 声明static int n;
};// 定义
int A::n = 0;A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();return 0;
}

在这里插入图片描述

想访问就就突破类域和访问界定符来访问。

class A
{
public:A(){++n;}A(const A& aa){++n;}//private:// 声明static int n;
};// 定义
int A::n = 0;A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();cout << aa1.n << endl;cout << aa2.n << endl;cout << A::n << endl;return 0;
}

在这里插入图片描述
如果是私有的就不能这样访问,可以提供一个共有的成员函数。

class A
{
public:A(){++n;}A(const A& aa){++n;}// static成员函数没有this指针static int GetN(){return n;}private:// 声明static int n;int a = 0;
};// 定义
int A::n = 0;A Func()
{A aa;return aa;
}int main()
{A aa1;A aa2;Func();cout << aa1.GetN() << endl;return 0;
}

在这里插入图片描述
static成员函数没有this指针

3.2 特性

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

有问题请指出,大家一起进步!!!

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

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

相关文章

9.WEB渗透测试-Linux基础知识-Linux用户权限管理(上)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;8.WEB渗透测试-Linux基础知识-Linux基础操作&#xff08;二&#xff09;-CSDN博客 用户管…

uniapp实现进度条组件

首先&#xff0c;在uniapp项目中创建一个自定义组件&#xff0c;可以命名为Progress.vue。在Progress.vue中&#xff0c;编写如下代码&#xff1a; <template><view class"progress"><view class"progress-bar" :style"{width: progr…

缓存淘汰策略看完这篇就够了

LFU 缓存淘汰算法 LFU 是 Least Frequently Used 的缩写&#xff0c;即 最少使用 缓存淘汰算法。LFU算法根据数据项在缓存中的访问频率来决定淘汰哪些数据项。访问频率越高 的数据项被认为是更重要的&#xff0c;访问频率越低 的数据项被认为是更不重要的。 LFU算法的具体工作原…

Kali Linux 2024.1

Kali Linux 2024.1刚刚发布&#xff0c;标志着这个备受欢迎的安全重点Linux发行版在今年的首次重大更新。以其先进的渗透测试和安全审计功能而闻名&#xff0c;它是安全专业人员和爱好者的首选工具。 Kali 2024.1 亮点 本次发布由 Linux 内核 6.6 提供支持&#xff0c;突出了…

C语言qsort函数介绍

前言 学到了函数指针&#xff0c;那这篇博客我们可以根据函数指针&#xff0c;了解一个函数qsort的应用与模拟实现 欢迎关注个人主页&#xff1a;小张同学zkf 若有疑问 评论区见 目录 1.回调函数 2.qsort函数使用 3.qsort模拟实现 1.回调函数 讲这个东西之前我们来认识一下…

mq基础类设计

消息队列就是把阻塞队列这样的数据结构单独提取成一个程序独立进行部署。——>实现生产者消费者模型。 但是阻塞队列是在一个进程内部进行的&#xff1b; 消息队列是在进程与进程之间进行实现的&#xff0c; 解耦合&#xff1a;就是在分布式系统中&#xff0c;A服务器调用B…

Tomcat -2

① 单机反向代理 7-2 代理服务器 7-5 tomcat 设置 7-3 测试&#xff1a; 代理服务器那里写什么就显示什么 ② 多机反向代理 实现动静分离和负载均衡 7-2 nginx 7-3 7-5 测试&#xff1a; 看静态&#xff1a; 看动态&#xff1a; ③ 反向代理多机多级 7-2 7-1 和 7-4 7-3…

【STM32】STM32学习笔记-读写内部FLASH 读取芯片ID(49)

00. 目录 文章目录 00. 目录01. FLASH概述02. 读写内部FLASH接线图03. 读写内部FLASH相关API04. 读写内部FLASH程序示例05. 读写芯片ID接线图06. 读写芯片ID程序示例07. 程序示例下载08. 附录 01. FLASH概述 STM32F10xxx内嵌的闪存存储器可以用于在线编程(ICP)或在程序中编程(…

华为OD机试 - 数字排列 - 深度优先搜索dfs算法(Java 2024 C卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述1、输入2、输出3、说明 四、解题思路五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&a…

外部存储器接口(EMIF)

外部存储器接口&#xff08;EMIF&#xff09; 该设备支持双核架构&#xff1b;为了为每个CPU子系统提供一个专用的EMIF&#xff0c;该设备支持两个EMIF模块——EMIF1和EMIF2。两个模块完全相同&#xff0c;具有相同的功能集&#xff0c;但具有不同的地址/数据大小。EMIF1在CPU…

Unity 角色控制(初版)

角色控制器组件&#xff0c;当然是将组件放在角色上了。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c1 : MonoBehaviour {// 获取角色控制器private CharacterController player;void Start(){// 加载角色控制器player …

机器学习 | 模型性能评估

目录 一. 回归模型的性能评估1. 平均平方误差(MSE)2. 平均绝对误差(MAE)3. R 2 R^{2} R2 值3.1 R 2 R^{2} R2优点 二. 分类模型的性能评估1. 准确率&#xff08;Accuracy&#xff09;2. 召回率&#xff08;Recall&#xff09;3. 精确率&#xff08;Precision&#xff09;4. …

大模型学习笔记五:RAG

文章目录 一、RAG介绍1)局限性2)通过检索增强生成二、RAG系统的基本搭建流程1)搭建流程简介2)文档的加载和切割3)检索引擎4)LLM接口封装5)prompt模板6)RAG Pipeline初探7)关键字检索局限性三、向量检索1)文本向量2)向量相似度计算3)向量数据库4)基于向量检索的RAG…

电源完整性设计的重要三步!

电源模块布局布线 电源模块是电子设备的能量来源&#xff0c;其性能与布局直接影响到整个系统的稳定性和效率。正确的布局和走线不仅能减少噪声干扰&#xff0c;还能确保电流的顺畅流通&#xff0c;从而提高整体性能。 1、电源模块布局 ● 源头处理&#xff1a;电源模块作为…

Java 面试题

Java 基础 以下代码执行结果&#xff1f; 示例1&#xff1a; public static void main(String[] args) {int a 0;Integer b 0;String c "0";String d new String("0");change(a, b, c, d);System.out.println(a "|" b "|" …

glibc

交叉编译器的glibc库位置&#xff1a; 用此交叉编译器编译的根文件系统对应的开发板上的GLIBC版本&#xff1a; 证明buildroot会使用交叉编译器自带的glibc库来对根文件系统进行编译。

如何在CentOS部署JumpServer堡垒机并实现无公网ip环境远程访问

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

通义千问1.5(Qwen1.5)大语言模型在PAI-QuickStart的微调与部署实践

作者&#xff1a;汪诚愚&#xff08;熊兮&#xff09;、高一鸿&#xff08;子洪&#xff09;、黄俊&#xff08;临在&#xff09; Qwen1.5&#xff08;通义千问1.5&#xff09;是阿里云最近推出的开源大型语言模型系列。作为“通义千问”1.0系列的进阶版&#xff0c;该模型推出…

【鸿蒙 HarmonyOS 4.0】登录流程

一、背景 登录功能在应用中是一个常用模块&#xff0c;此次使用 HarmonyOS 实现登录流程&#xff0c;包含页面呈现与网络请求。 二、页面呈现 三、实现流程 3.1、创建项目 构建一个ArkTS应用项目(Stage模型)&#xff0c;今天创建流程可查看官网教程&#xff1a;文档中心 目…

llc半桥开关电源基础知识2(电路图简化)

llc半桥开关电源拓扑图如下 稳态:LLC电源已经正常工作,已经输出电压稳定稳态:LLC电源已经正常工作,已经输出电压稳定。 我们在分析拓扑结构的时候,都是基于他已经正常稳定输出的时候来分析的,毕竟LC电源只要以工作啊,绝大多数时间都是工作在稳态。 具体电路图化简分析如…