类的初始化列表

news2024/12/24 7:08:36

文章目录

    • 一、初始化列表
        • 1、初始化列表的使用
        • 2、必须使用初始化列表来初始化的成员
    • 二、类型转换
        • 1、内置类型转换自定义类型
        • 2、自定义类型转换自定义类型
    • 三、静态成员变量(static)
        • 1、static修饰成员变量
        • 2、静态成员函数
    • 四、友元
    • 五、类里面再定义类
    • 六、匿名对象
        • 1、匿名对象的使用
        • 2、延长匿名对象的生命周期
    • 七、C++动态内存开辟
        • 1、new操作符开辟操作符
        • 2、delete操作符
        • 3、new跟malloc的区别
        • 4、delete跟free的区别
        • 5、定位new初始化

一、初始化列表

1、初始化列表的使用
  • 在构造函数体外使用冒号开始,逗号隔开,括号里面是初始化的值或一个表达式。
  • 每个成员只能在初始化列表初始化一次。
//在构造函数体内初始化
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

//初始化列表初始化
	Date(int year = 1, int month = 1, int day = 1)
		:_year(year)
		, _month(month)
		, _day(day)
	{
	}

上面这个日期类的初始化效果是一样的。

2、必须使用初始化列表来初始化的成员
  • 没有默认构造时的类类型成员必须使用初始化列表初始化
class stack
{
public:
	//构造函数
	//但没有缺省值,没有默认构造
	stack(int n)
	{
		_a = (int*)malloc(sizeof(int) * n);
		_top = 0;
		_capacity = n;
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

//用两个栈实现一个队列
class Myqueue
{
public:
	//自定义类型没有默认构造使用初始化列表初始化
	Myqueue(int n = 10)
		:_q1(n)
		, _q2(n)
	{

	}

private:
	stack _q1;
	stack _q2;
};
  • const 修饰的成员只能在初始化列表初始化
  • 引用成员变量只能在初始化列表初始化
class Myqueue
{
public:
	//自定义类型没有默认构造使用初始化列表初始化
	Myqueue(int& c, int n = 10)
		:_q1(n)
		, _q2(n)
		, x(10)
		, a(c)
	{

	}

private:
	stack _q1;
	stack _q2;
	const int x;
	int& a;
};
  • C++11支持在成员申明时给缺省值,这个缺省值是给初始化列表用的。
class Date
{
public:

private:
	int _year = 1;//给初始化列表缺省值
	int _month = 1;
	int _day = 1;
};
  • 初始化列表是按照成员声明的顺序初始化,不是按初始化列表的顺序初始化。

举例:

class A
{
public:
	A(int n)
		:_a1(n)
		,_a2(_a1)
	{

	}

	void print()
	{
		std::cout << _a1 << ' ' << _a2 << std::endl;
	}
private:
	int _a2 = 2;
	int _a1 = 1;
};

int main()
{
	A g(3);
	g.print();
	return 0;
}

输出结果:先初始_a2,用_a1给_a2初始化,此时_a1的值随机。
然后_a1再初始化为3。
在这里插入图片描述

二、类型转换

1、内置类型转换自定义类型

C++支持内置类型和类类型的相互转换

class A
{
public:
	A(int n)
		:_a1(n)
		,_a2(_a1)
	{

	}

	void print()
	{
		std::cout << _a1 << ' ' << _a2 << std::endl;
	}
private:
	int _a2 = 2;
	int _a1 = 1;
};

int main()
{
	A aa1 = 1;
	aa1.print();
	return 0;
}

用整形 1 创建了一个临时的A构造函数,拷贝构造给了aa1
但因为构造加拷贝构造太浪费了,就直接优化为直接构造
在这里插入图片描述
看上图,编译器只执行了一次构造函数。

  • 如果不想让隐式类型发生转换可以在前面加 explicit
	explicit A(int n)
		:_a1(n)
		,_a2(_a1)
	{
		std::cout << "A(int n)" << std::endl;
	}
  • 当有多个参数转换时,用大括号括起来
class A
{
public:
	A(int n, int m)
		:_a1(n)
		, _a2(m)
	{
		std::cout << "A(int n, int m)" << std::endl;
	}
	void print()
	{
		std::cout << _a1 << ' ' << _a2 << std::endl;
	}
private:
	int _a2 = 2;
	int _a1 = 1;
};

int main()
{ 
	A aa2 = { 1,1 };
	aa2.print();
	return 0;
}
2、自定义类型转换自定义类型

只要类型直接有关联就可以转换,这个关联需要借助构造函数。

class A
{
public:
	A(int n, int m)
		:_a1(n)
		, _a2(m)
	{
		
	}

	//访问成员
	int Get()const
	{
		return _a1 + _a2;
	}
private:
	int _a2 = 2;
	int _a1 = 1;
};

class B
{
public:
	B(const A& aa)
		:_b(aa.Get())
	{

	}
	void print()const
	{
		std::cout << _b << std::endl;
	}
private:
	int _b;
};
int main()
{ 
	A aa2 = { 1,1 };
	B bb1 = aa2;
	bb1.print();
	return 0;
}

需要注意的是需要借助Get()成员函数来访问私有的成员。

三、静态成员变量(static)

1、static修饰成员变量
  • 静态成员变量初始化在类外面。
  • 静态成员不只属于一个类的对象,而是属于所以类的对象,存储在静态区。
class F
{
public:
	int Get()
	{
		return _a;
	}

private:
	static int _a;//在类里面声明
};

int F::_a = 0;//在类外面初始化

int main()
{
	F f1;
	std::cout << f1.Get() << std::endl;
	return 0;
}

private限制的是类外面访问不到,提供一个类成员函数Get()就可以访问类成员变量了,但前提是创建了类的对象,通过对象调用函数。

2、静态成员函数

因为调用静态成员需要创建对象,所以为了能直接访问静态成员就有了静态成员函数。

  • 静态成员函数没有隐含this指针。
  • 静态成员函数只能访问静态成员变量。
class F
{
public:
	F()
	{
		++_a;
	}

	~F()
	{
		--_a;
	}
	static int Get()
	{
		return _a;
	}

private:
	static int _a;//在类里面声明
};

int F::_a = 0;//在类外面初始化

void Fcount()
{
	std::cout << F::Get() << std::endl;
}

int main()
{
	F f1;
	F f2;
	Fcount();
	return 0;
}

四、友元

  • 友元是一种突破封装的函数,在类里面使用friend关键词加上允许访问私有或保护的函数声明,可以让类外的函数访问私有或包含的类成员变量。
class Date
{
public:

	//友元申明
	friend std::ostream& operator<<(std::ostream& out, const Date& d);

	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};

std::ostream& operator<<(std::ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day <<"日" << std::endl;

	return out;
}

int main()
{
	Date d1(2023, 3, 4);
	std::cout << d1;
	return 0;
}
  • 成员函数也可以是别人的友元,友元不连续,例如:A是B的友元,B是C的友元,但A不是C的友元。
    一个函数可以是多个类的友元但需要以以声明。

五、类里面再定义类

在类里面定义一个类

class A
{
private:
	int _n;
	static int _a;

public:
	class B
	{
	private: 
		int b;
	public:
	};
};

int main()
{
	int size = sizeof(A);
	cout << size << endl;
	return 0;
}

在这里插入图片描述
可以观察占用空间大小,发现内部类没有实例化,就相当于只是一个定义没有创建对象,而静态成员变量存储在静态区,程序完全结束才销毁。

  • 内部类是一个独立的类,相较与全局类区别是受外部类域的限制,也受访问限定符限制。
    如果想创建B类,因为受到A类域的限制所以要指定类域后创建
    在这里插入图片描述
  • 内部类默认是外部类的友元
class A
{
private:
	int _n;
	static int _a;

public:
	class B
	{
	private: 
		int b;
	public:
		void fun(const A& h)
		{
			cout << _a << endl;
			cout << h._n << endl;
		}
	};
};

内部类直接访问外部静态成员变量,如果不是静态,指定对象也可以访问外部类的私有成员变量

在这里插入图片描述

六、匿名对象

1、匿名对象的使用

平时类创建的对象都是有名字的,没有名字的对象是匿名对象。

class A
{
private:
	int _n;

public:
	A(int n = 10)
		:_n(n)
	{
		cout << "A(int n)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};

int main()
{
	//有名对象
	A a(2);
	A a2;


	//匿名对象
	A(2);
	A();

	return 0;
}
  • 匿名对象在没有参数时也需要空括号
  • 匿名对象的声明周期只在当前这一行

在给自定义类型缺省值时使用匿名对象


void fun(A aa = A())
{
	
}
2、延长匿名对象的生命周期
  • 匿名对象可以应用,但匿名对象跟临时对象一样具有常性,需要加const修饰,从而延长了匿名对象的生命周期。
class A
{
private:
	int _n;

public:
	A(int n = 10)
		:_n(n)
	{
		cout << "A(int n)" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};

void fun(A aa = A())
{
	
}

int main()
{
	//有名对象
	A a(2);
	A a2;


	//匿名对象
	A(2);
	A();

	const A& a3 = A();//延长生命周期

	return 0;
}

七、C++动态内存开辟

1、new操作符开辟操作符

使用方法:
在这里插入图片描述

如果开辟多个同类型空间,相数组那样的,只是存储在堆上

int main()
{
	//开辟一个int类型大小的空间
	int* ptr = new int;
	double* ptr1 = new double;

	//开辟并初始化
	int* ptr2 = new int(3);
	double* ptr3 = new double(3.2);

	cout << *ptr << endl << *ptr1<<endl << *ptr2 << endl << *ptr3 << endl;

	//开辟多个数据
	int* ptr4 = new int[10];//都没初始化值随机
	//开辟多个并初始化
	int* ptr5 = new int[10] {1, 2, 3};//按顺序初始化没初始化的值为0
	cout << ptr4[3] << endl ;
	return 0;
}
2、delete操作符

功能是free()就是释放掉动态内存申请的空间,区别是更方便
释放一个对象:

int main()
{
	//开辟一个int类型大小的空间
	int* ptr = new int;
	delete ptr;
	return 0;
}

释放多个对象:

int main()
{
	int* ptr4 = new int[10];//都没初始化值随机
	delete[] ptr4;
	return 0;
}
3、new跟malloc的区别

除了方便写法简单外,在用于开辟类对象空间时有很大区别

class A
{
public:
	A(int n = 10)
	{
		_n = n;
	}
private:
	int _n;
};

int main()
{
	A* ptr1 = (A*)malloc(sizeof(A));

	A* ptr2 = new A;
	return 0;
}

在这里插入图片描述

通过监视功能可以看出主要区别是new开辟对象时会自动调用拷贝构造
也可以传参调用构造函数

A* ptr3 = new A(100);
  • 如果没有默认构造就会报错
4、delete跟free的区别

在堆类创建的对象进行释放时,有所不同
delete会调用析构函数再释放空间

在这里插入图片描述

5、定位new初始化

因为C++不支持显示调用构造函数,但是也可以通过new来调用


#include <iostream>

using namespace std;

class A
{
public:
	A(int n = 10)
		:_n(n)
	{
		cout << "A(int n)" << endl;
	}
private:
	int _n;
};

int main()
{
	A* ptr = (A*)operator new(sizeof(A));

	new(ptr)A(20);//调用拷贝构造

	return 0;
}

new(地址)类型(初始化的值),不传初始的值会调用默认构造

析构函数支持显示调用

#include <iostream>

using namespace std;

class A
{
public:
	A(int n = 10)
		:_n(n)
	{
		cout << "A(int n)" << endl;
	}
	
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int _n;
};

int main()
{
	A* ptr = (A*)operator new(sizeof(A));
	new(ptr)A;//调用拷贝构造

	ptr->~A();
	operator delete(ptr);

	return 0;
}

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

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

相关文章

大厂硬件梦:字节、腾讯“向首”,华为、小米“向手”

涉足可穿戴设备的大厂们&#xff0c;都抱着再造用户入口的野望&#xff0c;大模型治不好的痼疾&#xff0c;仍需继续前行寻找解药。 转载&#xff1a;科技新知 原创 作者丨茯神 编辑丨蕨影 苹果发布会再次令网友失望&#xff01;相比iPhone新机配色丑上热搜&#xff0c;反而苹…

Type-C与PD技术融合:重塑移动硬盘盒的未来

Type-C接口与PD充电技术&#xff1a;移动硬盘盒的革新之路 在数字化浪潮的汹涌澎湃中&#xff0c;我们的生活与工作环境被各式各样的电子设备所包围。从智能手机到平板电脑&#xff0c;从笔记本电脑到高清显示器&#xff0c;每一个设备都在以惊人的速度迭代更新&#xff0c;推…

集运系统:让海外集运包裹管理更简单!

随着全球化贸易的快速发展&#xff0c;海外包裹代收、仓储管理、退换货、国际快递等服务需求日益增长。集运系统作为一种专为海外客户提供一站式服务的软件系统&#xff0c;通过整合物流信息、管理订单、跟踪货物等功能&#xff0c;有效满足这些需求。本文将介绍集运系统的功能…

Python数据类型详解:这12个类型你都知道吗?

在Python中&#xff0c;数据类型是编程的基石&#xff0c;它们定义了可以操作的数据的种类。Python是一种动态类型语言&#xff0c;意味着你不需要显式地声明变量的类型&#xff1b;Python解释器会自动推断出变量所存储数据的类型。Python提供了多种内置数据类型&#xff0c;这…

立足本土,面向全球 | 全视通闪耀亮相Medical Fair Asia新加坡医疗展

Medical Fair Asia是亚洲地区最大的医疗设备、医疗器械和医疗技术展览会之一&#xff0c;自1997年创办以来&#xff0c;每两年在新加坡举办一次。该展会不仅是新加坡医疗行业交流的龙头平台&#xff0c;也是亚洲乃至全球医疗企业和专业人士共聚一堂、展示最新产品和技术的重要舞…

人情债VS利息债:如何更好的借贷?

在人生的旅途中&#xff0c;谁不曾遭遇资金紧张的瞬间&#xff1f;面对这样的挑战&#xff0c;是向亲朋好友伸出援手&#xff0c;还是探索贷款之路&#xff0c;成为了一个值得深思的问题。今天&#xff0c;我们就以小刘的经历为镜&#xff0c;共同探讨这一话题。 故事的主角小刘…

Modbus协议03:Modbus功能码和协议分类

视频链接&#xff1a;【3】Modbus协议功能码说明_哔哩哔哩_bilibili【3】Modbus协议功能码说明是【直播回放】小白也可以听懂的Modbus协议讲解的第3集视频&#xff0c;该合集共计4集&#xff0c;视频收藏或关注UP主&#xff0c;及时了解更多相关视频内容。https://www.bilibili…

详解:冒泡排序

1.是什么 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法。它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序完成…

C语言-数据结构 无向图克鲁斯卡尔算法(Kruskal)邻接矩阵存储

相比普里姆算法来说&#xff0c;克鲁斯卡尔的想法是从边出发&#xff0c;不管是理解上还是实现上都更简单&#xff0c;实现思路&#xff1a;我们先把找到所有边存到一个边集数组里面&#xff0c;并进行升序排序&#xff0c;然后依次从里面取出每一条边&#xff0c;如果不存在回…

python vtk 绘制圆柱体和包围盒

基本的代码如下&#xff0c; import vtkcylinder vtk.vtkCylinderSource() cylinder.SetRadius(3.0) cylinder.SetHeight(10.0) cylinder.SetResolution(50)boundsFilter vtk.vtkOutlineFilter() boundsFilter.SetInputConnection(cylinder.GetOutputPort())mapper vtk.vtk…

UQpy | 不确定性量化Python工具箱推荐

UQpy, "Uncertainty Quantification with Python,"是一个通用的 Python 工具箱&#xff0c;用于对物理和数学系统模拟中的不确定性进行建模。该代码被组织为一组以不确定性量化&#xff08;UQ&#xff09;的核心功能为中心的模块&#xff0c;如下所示。这些模块各不相…

无线安全(WiFi)

免责声明:本文仅做分享!!! 目录 WEP简介 WPA简介 安全类型 密钥交换 PMK PTK 4次握手 WPA攻击原理 网卡选购 攻击姿态 1-暴力破解 脚本工具 字典 2-Airgeddon 破解 3-KRACK漏洞 4-Rough AP 攻击 5-wifi钓鱼 6-wifite 其他 WEP简介 WEP是WiredEquivalentPri…

I/O 多路复用:`select`、`poll`、`epoll` 和 `kqueue` 的区别与示例

I/O 多路复用是指在一个线程内同时监控多个文件描述符&#xff08;File Descriptor, FD&#xff09;&#xff0c;以便高效地处理多个 I/O 事件。在 UNIX/Linux 和 BSD 系统中&#xff0c;select、poll、epoll、kqueue 都是实现 I/O 多路复用的系统调用。它们各有特点&#xff0…

MYMPay码支付开源版系统源码

MYMPay码支付开源版系统源码 前言安装环境&#xff1a;首页图片用户中心管理后台 部分源码领取源码下期更新 前言 最新版MYMPay码支付开源版系统源码_个人免签支付_聚合支付系统 安装环境&#xff1a; PHP&#xff1a;7.0-8.2 (推荐使用7.4)需要安装Xload 扩展MySQL&#xf…

Linux基础入门篇

一.Linux概述 我们一般所说的Liunx表示的是Linux的内核部分&#xff0c;Liunx 发行版是在其内核的基础上进行了对其他软件的集成&#xff0c;更加方便了用户的使用 Liunx的结构&#xff1a; 目前市场上使用的Linux大多为CenterOS,一些微型的开发中会使用到Ubuntu,两者在一些指…

【刷题】Day4--密码检查

Hi&#xff01; 今日刷题&#xff0c;小白一枚&#xff0c;欢迎指导 ~ 【链接】 密码检查_牛客题霸_牛客网 【思路】 依次根据规则判断密码是否合格。while里嵌套个for循环&#xff0c;来进行密码的多组输入&#xff0c;for循环进行一次代表判断一个密码串&#xff1b;规则…

STM32+ESP01连接到机智云

机智云,全球领先的智能硬件软件自助开发及物联网(iot)云服务平台。机智云平台为开发者提供了自助式智能硬件开发工具与开放的云端服务。通过傻瓜化的自助工具、完善的SDK与API服务能力最大限度降低了物联网硬件开发的技术门槛&#xff0c;降低开发者的研发成本&#xff0c;提升…

添加选择登录ssh终端

吼吼,这次成了一个小的瑞士军刀了 … …

2.Jmeter安装配置,核心目录详情,组件和作用域

一、Jmeter安装配置以及核心目录详情 Jmeter基于java语言来开发&#xff0c;java需要jdk环境。 1.安装jdk并且配置jdk的环境变量。 2.jmeter只需要解压就可以使用了。 3.在D:\apache-jmeter-5.5\bin目录下双击jmeter.bat文件就可以启动使用了 backups&#xff1a;自动备份的目录…

OpenHarmony(鸿蒙南向开发)——轻量系统STM32F407芯片移植案例

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——轻量和小型系统三方库移植指南…