【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 访问限定符的限制

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字经济的下一步:Web3的潜力与前景

引言&#xff1a; 随着区块链技术的迅速发展&#xff0c;数字经济正迎来新的变革时代。在这个数字化时代&#xff0c;Web3作为区块链技术的延伸和演进&#xff0c;正在成为全球数字经济发展的重要方向。本文将深入探讨Web3的潜力与前景&#xff0c;以及它对数字经济发展的深远…

Vue2+ElementUI列表、表格组件的封装

Vue2ElementUI列表组件的封装&#xff1a;引言 在日常开发中&#xff0c;我们经常会遇到需要展示列表数据的场景。ElementUI 提供的 el-table 组件是一个功能强大的表格组件&#xff0c;可以满足大部分的需求。但是&#xff0c;在实际应用中&#xff0c;我们往往需要根据业务需…

【嵌入式——QT】QTreeWidget

QTreeWidget类是创建和管理目录树结构的类&#xff0c;QTreeWidget每一个节点都是一个QTreeWidgetItem对象&#xff0c;添加一个节点前需先创建。QTreeWidget类是一个便利类&#xff0c;它提供了一个标准的树widget&#xff0c;具有经典的基于item的界面&#xff0c;类似于Qt 3…

2024智能遥控器行业市场规模及技术水平分析

智能遥控器&#xff0c;主要是由集成电路板和用来生产不同讯息的按钮所组成&#xff0c;内装有一个中央处理器芯片&#xff0c;芯片在制造时就将设备各种菜单码值信息输入其中&#xff0c;遥控发射器只要发出与之对应的密码就可以实现对设备的控制。无线遥控技术原理就是发射机…

【kubernetes】关于k8s集群的污点和容忍,以及k8s集群的故障排查思路

目录 一、污点 关于污点的增删改查 验证污点的作用——NoExecute ​编辑 验证污点的作用——NoSchedule 验证污点的作用——PreferNoSchedule 二、容忍 三、关于cordon 和 drain 四、Pod启动阶段 五、关于pod的五种状态 六、k8s常见的排障手段 针对组件故障 针对pod…

短视频直播电商项目运营建设规划方案商业计划

【干货资料持续更新&#xff0c;以防走丢】 短视频直播电商项目运营建设规划方案商业计划 部分资料预览 资料部分是网络整理&#xff0c;仅供学习参考。 PPT&#xff08;完整资料包含以下内容&#xff09; 目录 短视频直播运营方案 一、云零售电商运营体系搭建&#xff1a; …

Arduino与processing之间的通信——进阶版

本次需要实现Arduino获取板子的偏转角度并通过串口发送给processing&#xff0c;processing部分根据传输过来的各个轴的偏转角度建立对应偏转角度的3D模型。 这就涉及了两个轴正负方向的偏转&#xff0c;我的实现思路是使用串口传输 字母数字 格式的信息&#xff0c;字母用来判…

如何在手机上中恢复已删除的照片

市场上有大量用于恢复手机已删除照片的应用程序。您可以尝试任何合法的应用程序来恢复意外删除的视频。其中一些应用程序包括 奇客数据恢复、Disk Drill等。 恢复已删除的 Android 照片 如果您不小心从 Android 设备中删除了任何重要视频&#xff0c;无需惊慌。您可以按照这些…

滑动窗口

题目 思路 对于一个数组区间的最值&#xff0c;可以开辟一个队列记录&#xff08;当然这里不能叫队列只是和队列相似&#xff0c;习惯性叫法)。 每个区间的最值等于队首元素。扫描数组时&#xff0c;如果该元素大于队尾元素&#xff08;取最大值时&#xff09;将该队尾元素出队…

利用Python爬取高德地图全国地铁站点信息

利用Python中的requests库进行地铁站点信息的获取,同时将数据保存在本机excel中 # 首先引入所需要的包 import requests from bs4 import BeautifulSoup import pandas as pd import json# 发送 GET 请求获取网页内容 url http://map.amap.com/subway/index.html response r…

06.QT信号和槽-1

一、信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮"是一个事件&#xff0c;"用户关闭窗口"也是一个事件。每个事件都会发出一个信号&#xff0c;例如用户点击按钮会发出"按钮被点击"的信号&#xff…

Ubuntu的apt、apt-get和apt-cache命令

原文&#xff1a;apt 和 apt-get 之间有什么区别&#xff1f; https://aws.amazon.com/cn/compare/the-difference-between-apt-and-apt-get/ 陈拓转载&#xff0c;2023/11/23&#xff0c;添加了举例。 apt 和 apt-get 之间有什么区别&#xff1f; apt 和 apt-get 都是命令行…

三位数反转问题易被忽略的两大细节

【题目描述】 输入一个三位数&#xff0c;分离出它的百位、十位和个位&#xff0c;反转后输出。 【样例输入】 127 【样例输出】 721 这个问题并不难&#xff0c;只需要两步&#xff1a; ①将这个三位数分离成三个数字&#xff08;参见“整数的分离与合成”一文&#xff…

lv20 QT事件5

1 事件模型 2 事件处理 virtual void keyPressEvent(QKeyEvent *event) virtual void keyReleaseEvent(QKeyEvent *event) virtual void mouseDoubleClickEvent(QMouseEvent *event) virtual void mouseMoveEvent(QMouseEvent *event) virtual void mousePressEvent(QMou…

【大厂AI课学习笔记NO.59】(12)过拟合与欠拟合

拟合就是调整参数和模型&#xff0c;让结果无限接近真实值的过程。 我们先来了解个概念&#xff1a; 偏差-方差窘境&#xff08;bias-variance dilemma&#xff09;是机器学习中的一个重要概念&#xff0c;它涉及到模型选择时面临的权衡问题。 偏差&#xff08;Bias&#xf…

自建Redis蜜罐以捕获和分析潜在攻击

一、引言 随着网络攻击的日益频繁和复杂&#xff0c;传统的防御措施往往难以应对。蜜罐作为一种主动防御技术&#xff0c;通过模拟有价值的服务来吸引攻击者&#xff0c;从而收集和分析攻击数据&#xff0c;提高网络安全性。本文将介绍如何自建一个Redis蜜罐&#xff0c;以捕获…

转转测试环境docker化实践

【软件测试面试突击班】2024吃透软件测试面试最全八股文攻略教程&#xff0c;一周学完让你面试通过率提高90%&#xff01;&#xff08;自动化测试&#xff09; 测试环境对于任何一个软件公司来讲&#xff0c;都是核心基础组件之一。转转的测试环境伴随着转转的发展也从单一的几…

【开源】JAVA+Vue.js实现农家乐订餐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 用户2.2 管理员 三、系统展示四、核心代码4.1 查询菜品类型4.2 查询菜品4.3 加购菜品4.4 新增菜品收藏4.5 新增菜品留言 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的农家乐订餐系统&#xff0c…

MS1030超声波流量高精度测量电路

产品简述 MS1030 是一款针对超声波流量高精度测量电路&#xff0c;它具有高 精度&#xff0c;高稳定性&#xff0c;高效率的特点。它的测量精度 15ps &#xff0c;测量范 围 500ns  4ms4MHz 。在第一波模式情况下&#xff0c;内部比较器的 offset 可编程范围为 127…

type.GetFields() 获取不到,改用type.DeclaredFields

StatisticQuery 类 private Dictionary<string, DateTime> GetTBHBDate(StatisticQuery model, string field){Dictionary<string, DateTime> dic new Dictionary<string, DateTime>();DateTime TB new DateTime();//同比开始日期 &#xff08;年&#xff…