【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.mzph.cn/news/700422.shtml

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

相关文章

深入了解Kettle工具:数据集成与转换的利器

深入了解Kettle工具&#xff1a;数据集成与转换的利器 在当今数据驱动的时代&#xff0c;企业需要处理大量来自不同来源的数据&#xff0c;并将其整合到统一的数据仓库或数据湖中&#xff0c;以便进行进一步的分析和挖掘。而在这个过程中&#xff0c;数据集成与转换工具扮演着…

Android BitmapDrawable.bitmap与BitmapFactory.decodeResource获取不到原始图像素级真实宽高,Kotlin

Android BitmapDrawable.bitmap与BitmapFactory.decodeResource获取不到原始图像素级真实宽高&#xff0c;Kotlin 当一个图片放在ImageView里面后&#xff0c;用以下方式获取图的宽高&#xff1a; val bmp1 (this.drawable as BitmapDrawable).bitmapLog.d("fly", &…

直流恒流源电路

简介 使用电流源稳压器芯片搭建&#xff0c;该恒流源输出电流Iout1OuA*R2/R1,该电路可用于电阻阻值检测等相关场合。 注意&#xff1a;支持最大电流为200mA LT3092IST#PBF 简介 原理图展示

如何查看电脑使用记录?保障个人隐私和安全

查看电脑使用记录是了解电脑活动的一种重要方式&#xff0c;可以帮助用户追踪应用程序的使用情况、登录和关机时间、文件的访问记录等。在本文中&#xff0c;我们将介绍如何查看电脑使用记录的三个方法&#xff0c;以分步骤详细说明如何查看电脑使用记录&#xff0c;帮助用户更…

128 Linux 系统编程6 ,C++程序在linux 上的调试,GDB调试

今天来整理 GDB 调试。 在windows 上我们使用vs2017开发&#xff0c;可以手动的加断点&#xff0c;debug。 那么在linux上怎么加断点&#xff0c;debug呢&#xff1f;这就是今天要整理的GDB调试工具了。 那么有些同学可能会想到&#xff1a;我们在windows上开发&#xff0c;…

UML---活动图

活动图概述 活动图&#xff08;Activity Diagram&#xff09;是UML&#xff08;Unified Modeling Language&#xff0c;统一建模语言&#xff09;中的一种行为建模工具&#xff0c;主要用于描述系统或业务流程中的一系列活动或操作。活动图通常用于描述用例中的行为&#xff0c…

opengl pyqt 显示文字

目录 效果图 效果图 import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QOpenGLWidgetfrom OpenGL.GL import * from OpenGL.GLUT import * from OpenGL.GLU import *class OpenGLWidget(QOpenGLWidget):def __init__(self, parentNone):super(OpenGLWidget…

开源分子对接程序rDock的安装及使用流程

欢迎浏览我的CSND博客&#xff01; Blockbuater_drug …点击进入 前言 本文介绍开源分子对接程序rDock在Linux Ubuntu 22.04系统上的conda安装、编译安装过程及程序使用流程。 一、rDock是什么&#xff1f; rDock来源 rDock是一个快速、多功能的开源对接程序&#xff0c;可用…

IOS不使用默认的mainStroryboard作为首个controller的方法

步骤1&#xff1a; 删除info.plist文件下的一条配置&#xff0c;如图 步骤2&#xff1a; 编辑AppDelegate.m&#xff0c;参考以下代码 interface AppDelegate () //property (strong, nonatomic) UIWindow * window; property(nonatomic,strong) UIWindow * win; property(…

【Ubuntu】使用WSL安装Ubuntu

WSL 适用于 Linux 的 Windows 子系统 (WSL) 是 Windows 的一项功能&#xff0c;可用于在 Windows 计算机上运行 Linux 环境&#xff0c;而无需单独的虚拟机或双引导。 WSL 旨在为希望同时使用 Windows 和 Linux 的开发人员提供无缝高效的体验。安装 Linux 发行版时&#xff0c…

K8s安全一

Kubernetes是一个开源的&#xff0c;用于编排云平台中多个主机上的容器化的应用&#xff0c;目标是让部署容器化的应用能简单并且高效的使用, 提供了应用部署&#xff0c;规划&#xff0c;更新&#xff0c;维护的一种机制。其核心的特点就是能够自主的管理容器来保证云平台中的…

医院信息系统(HIS):一文扫盲,算是所有信息系统里面复杂的

大家好&#xff0c;我是贝格前端工场&#xff0c;本期继续分享常见的B端管理系统&#xff0c;欢迎大家关注&#xff0c;如有B端写系统界面的设计和前端需求&#xff0c;可以联络我们。 一、什么是HIS系统 HIS系统&#xff08;Hospital Information System&#xff09;是医院信…

K线实战分析系列之三:吞没形态

K线实战分析系列之三&#xff1a;吞没形态 一、吞没形态二、看涨吞没形态三、看跌吞没形态四、吞没形态判别标准 一、吞没形态 两根或两根以上的K线形成的组合形态&#xff0c;吞没形态就是一种主要的反转形态。 这个形态由两根K线组成&#xff0c;前短后长&#xff0c;一阴一…

第三百六十五回

文章目录 1. 概念介绍2. 方法与信息2.1 获取方法2.2 详细信息 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何获取设备信息"相关的内容&#xff0c;本章回中将介绍如何获取App自身的信息.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

LeetCode LCR 085.括号生成

正整数 n 代表生成括号的对数&#xff0c;请设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 示例 2&#xff1a; 输入&#x…

备战蓝桥杯—— 双指针技巧巧答链表1

对于单链表相关的问题&#xff0c;双指针技巧是一种非常广泛且有效的解决方法。以下是一些常见问题以及使用双指针技巧解决&#xff1a; 合并两个有序链表&#xff1a; 使用两个指针分别指向两个链表的头部&#xff0c;逐一比较节点的值&#xff0c;将较小的节点链接到结果链表…

leetcode单调栈

739. 每日温度 请根据每日 气温 列表&#xff0c;重新生成一个列表。对应位置的输出为&#xff1a;要想观测到更高的气温&#xff0c;至少需要等待的天数。如果气温在这之后都不会升高&#xff0c;请在该位置用 0 来代替。 例如&#xff0c;给定一个列表 temperatures [73, …

【Linux】 logout命令使用

logout命令 Linux logout命令用于前登录的用户退出系统。 它会终止当前用户的会话并返回到登录界面或者重新登录。当使用logout命令时&#xff0c;系统会关闭所有与当前用户相关的进程和程序&#xff0c;并释放占用的资源。 使用logout命令可以方便地切换用户或者注销当前用…

vue教程

v 创建一个vue实例插值表达式{{}}vue响应式特性vue指令v-if vs. v-show 指令v-else-if 指令v-on指令 注册监听内联语句methods中的函数名![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/8b9d81539ba74e6691b27694813e0f65.png)v-on 调用传参 v-bind 动态的设置html…

Machine Learning - 机器学习笔记

文章目录 1. 机器学习简介1.1 机器学习是什么&#xff1f; 2. 机器学习分类2.1 监督学习2.2 无监督学习 3. 初识机器学习3.1 线性回归模型3.2 代价函数3.2.1 代价函数公式3.2.2 理解代价函数 4. 了解梯度下降算法4.1 梯度下降4.2 梯度下降的实现4.3 理解梯度下降4.4 学习率4.5 …