浅谈C++|构造.析构函数篇

news2025/1/18 6:55:10


一对象的初始化和处理

1.1构造函数和析构函数

C++拥有构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器提供的构造函数和析构函数是空实现。

·构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

·析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

语法:

构造函数语法:类名(){}

  1.构造函数,没有返回值也不写void

  2.函数名称与类名相同

  3.构造函数可以有参数,因此可以发生重载

  4.程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

析构函数语法:~类名(){}

  1.析构函数,没有返回值也不写void

  2.函数名称与类名相同,在称前加上符号

  3.析构函数不可以有参数,因此不可以发生重载

  4.程序在对象销毁前会自动调用析构,

代码: 

#include <iostream>
using namespace std;
class person {
public:
	person() {
		cout << "person 构造函数调用" << endl;
	}
	~person() {
		cout << "person 析构函数调用" << endl;
	}

};
void func() {
	person a;
}
int main() {
	func();
	return 0;
}

 1.2构造函数的分类和调用

两种分类方式:

  按参数分为:有参构造和无参构造

  按类型分为:普通构造和拷贝构造

三种调用方式:

  括号法

  显示法

  隐式转换发

1.2.1构造函数分类

(1)有参和无参构造函数

代码:

#include <iostream>
using namespace std;
class person {
public:
	person() {
		cout << "person 无参构造函数调用" << endl;
	}
	person(int a) {
		cout << "person 有参构造函数调用" << endl;
	}
	~person() {
		cout << "person 析构函数调用" << endl;
	}

};
void func() {
	person a(1);
}
int main() {
	func();
	return 0;
}

(2)普通和拷贝构造函数 

 代码:

#include <iostream>
using namespace std;
class person {
public:
	int age;
	person() {
		cout << "person的普通构造函数" << endl;
	}
	person(const person& p) {
		age = p.age;
		//可以将传入的人的所有属性,拷贝到神上
		cout << "person的拷贝构造函数" << endl;
	}
};
void func() {
	//1.括号法
	person p1;
	p1.age = 10;
	person p2(p1);
	cout << p2.age << endl;
}
int main() {
	func();
	return 0;
}

1.2.2构造函数的调用方式

括号法

显示法

隐式转换发

(1)括号法:

#include <iostream>
using namespace std;
class person {
public:
	int age;
	person() {
		cout << "person的普通构造函数" << endl;
	}
	person(int a) {
		age = a;
		cout << "person的普通构造函数" << endl;
	}
	person(const person& p) {
		age = p.age;
		//可以将传入的人的所有属性,拷贝到神上
		cout << "person的拷贝构造函数" << endl;
	}
};
void func() {
	//1.括号法
	person p1;       //默认
	p1.age = 10;
	person p2(20);   //有参
	person p3(p1);   //拷贝

	//2.
}
int main() {
	func();
	return 0;
}

注意: person p() 会被认为是函数声明,并不是调用默认构造

(2)显示法:

#include <iostream>
using namespace std;
class person {
public:
	int age;
	person() {
		cout << "person的普通构造函数" << endl;
	}
	person(int a) {
		age = a;
		cout << "person的普通构造函数" << endl;
	}
	person(const person& p) {
		age = p.age;
		//可以将传入的人的所有属性,拷贝到神上
		cout << "person的拷贝构造函数" << endl;
	}
};
void func() {
	//2.显示法
	person p1;       //默认
	p1.age = 10;
	person p2=person(20);   //有参
	person p3=person(p1);   //拷贝

	//2.
}
int main() {
	func();
	return 0;
}

1.person(20)称为匿名对象,当前行执行后系统会立即回收匿名对象

2.不要用拷贝构造函数初始化匿名对象,person(p3) ->person  p3;相当于重新定义一个p3,发生重定义错误。

(3) 隐式转换法:

#include <iostream>
using namespace std;
class person {
public:
	int age;
	person() {
		cout << "person的普通构造函数" << endl;
	}
	person(int a) {
		age = a;
		cout << "person的普通构造函数" << endl;
	}
	person(const person& p) {
		age = p.age;
		//可以将传入的人的所有属性,拷贝到神上
		cout << "person的拷贝构造函数" << endl;
	}
};
void func() {
	//3.隐式转换发
	person p1;       //默认
	person p2=10;    //相当于person p2=person(10);
	person p3 = p2;  //相当于person p3 = person(p2);
}
int main() {
	func();
	return 0;
}

1.3拷贝构造函数调用时机

1.使用一个已经创建完毕的对象来初始化一个新对象。

2.值传递的方式给函数参数传值

3.以值方式返回局部对象

 1.3.1旧对象创建新对象

代码:

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int b;
	person() {
		cout << "person的无参构造函数" << endl;
	}
	person(int a1) {
		a = a1;
		cout << "person的有参构造函数" << endl;
	}
	person(const person &p) {
		a = p.a;
		cout << "person的拷贝构造函数" << endl;
	}
	~person() {
		cout << "person的析构函数" << endl;
	}
};
void fun() {
	person A(10);
	person B(A);
	cout << B.a << ' ' << B.b << endl;
}
int main() {
	fun();
	return 0;
}

 1.3.2值传递的方式给函数参数传值

作为函数值传递时,只会复制拷贝函数中已将定义要拷贝的变量,其余的即使已经外部定义了,只要拷贝函数中没有指明要拷贝,形参就不会拷贝。

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int b;
	int c;
	person() {
		cout << "person的无参构造函数" << endl;
	}
	person(int a1) {
		a = a1;
		cout << "person的有参构造函数" << endl;
	}
	person(const person &p) {
		a = p.a;
		cout << "person的拷贝构造函数" << endl;
	}
	~person() {
		cout << "person的析构函数" << endl;
	}
};
void fun(person A) {
	cout << A.a << ' ' << A.b <<' '<<A.c << endl;
}
int main() {
	person A(10);
	A.b = 90;
	cout << A.a << ' ' << A.b << ' ' << A.c << endl;
	fun(A);
	return 0;
}

1.3.3以值方式返回局部对象

同做做参数一样,也只复制拷贝函数中定义要复制的部分,并不是完全复制。

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int b;
	int c;
	person() {
		cout << "person的无参构造函数" << endl;
	}
	person(int a1) {
		a = a1;
		cout << "person的有参构造函数" << endl;
	}
	person(const person &p) {
		a = p.a;
		cout << "person的拷贝构造函数" << endl;
	}
	~person() {
		cout << "person的析构函数" << endl;
	}
};
person fun() {
	person A(10);
	A.b = 90;//已经赋值,但是形参还是随机值
	cout << A.a << ' ' << A.b << ' ' << A.c << endl;
	return A;
	
}
int main() {
	person A=fun();
	cout << A.a << ' ' << A.b << ' ' << A.c << endl;
	return 0;
}

 1.4构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数,对属性进行值拷贝(全部)

构造函数调用规则如下:

1.如果用户定义有参构造函数,c+不在提供默认无参构造,但是会提供默认拷贝构造

2.如果用户定义拷贝构造函数,C++不会再提供其他构造函数

代码:

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int b;
	int c;
	
	person(int a1) {
		a = a1;
		cout << "person的有参构造函数" << endl;
	}
	
	~person() {
		cout << "person的析构函数" << endl;
	}
};
person fun() {
	person A(10);
	A.b = 90;
	//person B;   报错
	return A;
	
}
int main() {
	fun();
	return 0;
}

1.5深拷贝和浅拷贝

浅拷贝就是简单的赋值操作,深拷贝就是

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int* b;
	person(int a1, int b2) {
		a = a1;
		b = new int(b2);
	}
	person(const person &p) {  //浅拷贝
		a = p.a;
		b = p.b;
	}
	~person() {  //浅拷贝
		if (b != NULL) {
			delete b;
			b = NULL;
		}
	}
};
void fun() {
	person a(10,90);
	person b(a);
	cout << b.a << ' ' << *b.b << endl;
}
int main() {
	fun();
	return 0;
}

 此时代码会报错,因为此时有两个析构函数,因此会是否两次相同地址的空间,此时要改为深拷贝。

代码: 

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int* b;
	person(int a1, int b2) {
		a = a1;
		b = new int(b2);
	}
	person(const person &p) {  //深拷贝
		a = p.a;
		b = new int(*(p.b));
	}
	~person() {  
		if (b != NULL) {
			delete b;
			b = NULL;
		}
	}
};
void fun() {
	person a(10,90);
	person b(a);
	cout << b.a << ' ' << *b.b << endl;
}
int main() {
	fun();
	return 0;
}

 

  1.6初始化列表

C++提供了初始化列表语法,用来初始化属性。

 语法:构造函数()  :  属性值1(值1),属性值2(值2)....... { }

代码:

#include <iostream>
using namespace std;
class person {
public:
	int a;
	int b;
	int c;
	person(int a1,int b1,int c1) :a(a1), b(b1), c(c1) {  //初始化列表

	}
};
void fun() {
	person p(30, 3,78);
	cout << p.a << ' ' << p.b << ' ' << p.c << endl;
}
int main() {
	fun();
	return 0;
}

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

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

相关文章

vue学习之组件化开发

1. vue创建 基于vue2的项目 vue create vue-cli-learning 选择 “Manually select features” 取消勾选“Linter / Formatter” 选择“2.x” 选择“In package.json” 输入“N” 回车

elasticsearch索引同步

通常项目中使用elasticsearch需要完成索引同步&#xff0c;索引同步的方法很多&#xff1a; #1、针对实时性非常高的场景需要满足数据的及时同步&#xff0c;可以同步调用&#xff0c;或使用Canal去实现。 1&#xff09;同步调用即在向MySQL写数据后远程调用搜索服务的接口写…

Springboot -- DOCX转PDF(二)

之前记录了按照模板生成 DOCX 文件、并转换为 PDF 文件的方法 https://blog.csdn.net/qq_40096897/article/details/131979177?spm1001.2014.3001.5501 但是使用效果并不是很理想&#xff0c;转换完的 PDF 格式和原本的文档格式不匹配。所以在此重新找了一个文件转 PDF 的方法…

SpringMVC中的请求重定向和转发

一.概述 当处理器对请求处理完毕后&#xff0c;向其它资源进行跳转时&#xff0c;有两种跳转方式&#xff1a;请求转发与重 定向。而根据所要跳转的资源类型&#xff0c;又可分为两类&#xff1a;跳转到页面与跳转到其它处理器。注意&#xff0c;对于请求转发的页面&#xff0c…

算法通过村第八关-树(深度优先)青铜笔记|经典算法题目

文章目录 前言1. 二叉树里面的双指针1.1 判断两棵树是否相同1.2 对称二叉树1.3 合并二叉树 2. 路径专题2.1 二叉树的所有路径2.2 路径总和 3. 翻转的妙用总结 前言 提示&#xff1a;人类的底里是悲伤&#xff0c;我们都在用厚重的颜料&#xff0c;覆盖那些粗糙的线稿。--张皓宸…

Vulnhub实战-prime1

前言 VulnHub 是一个面向信息安全爱好者和专业人士的虚拟机&#xff08;VM&#xff09;漏洞测试平台。它提供了一系列特制的漏洞测试虚拟机镜像&#xff0c;供用户通过攻击和漏洞利用的练习来提升自己的安全技能。本次&#xff0c;我们本次测试的是prime1。 一、主机发现和端…

Verdi实现信号的平移

在Verilog/System verilog中&#xff0c;# xxx可以实现延迟指定时间的功能&#xff0c;而在使用verdi查看信号波形并进行分析时&#xff0c;同样也可以实现类似的功能。 (注&#xff1a;这种信号平移是有其应用场景的&#xff0c;例如&#xff0c;在某些仿真模型中&#xff0c;…

Vue2电商前台项目——完成加入购物车功能和购物车页面

Vue2电商前台项目——完成加入购物车功能和购物车页面 文章目录 Vue2电商前台项目——完成加入购物车功能和购物车页面一、加入购物车1、路由跳转前先发请求把商品数据给服务器&#xff08;1&#xff09;观察接口文档&#xff08;2&#xff09;写接口&#xff08;3&#xff09;…

知识深度 VS 知识广度

知识深度&#xff1a;帮助更快的朝着目标进。 发知识广度&#xff1a;帮助找到最优的路径。 职业生涯的前期需要执行力&#xff0c;因此需要更多的锻炼知识深度。越往后需要更多的做决策&#xff0c;因此要更多提升知识广度。

git 远程名称 远程分支 介绍

原文&#xff1a; 开发者社区> 越前君> 细读 Git | 让你弄懂 origin、HEAD、FETCH_HEAD 相关内容 读书笔记&#xff1a;担心大佬文章搬家&#xff0c;故整理此学习笔记 远程名称&#xff08;Remote Name&#xff09; Origin 1、 origin 只是远程仓库的一个名称&#xff…

代码管理工具git1

ctrl 加滚轮 放大字体 在计算机任意位置单击右键&#xff0c;选择&#xff1a;&#xff1a;Git Bash Here git version git清屏命令&#xff1a;ctrl L查看用户名和邮箱地址&#xff1a; $ git config user.name$ git config user.email修改用户名和邮箱地址&#xff1a;$ git…

防止泄露,保护隐私!如何清除你的谷歌搜索历史记录

按照以下说明学习如何从你的谷歌帐户、谷歌Chrome浏览器、谷歌iOS或Android应用程序或谷歌应用程序中删除你的谷歌历史记录。 如何从你的谷歌帐户中删除搜索历史记录 清除你的谷歌搜索历史并不意味着谷歌实际上会删除你的搜索数据。谷歌仍然会记录你如何以及何时使用某些功能…

数据结构——二叉树提升

二叉树题型练习 前言一、节点个数以及高度等二、二叉树OJ题二叉树的前序遍历二叉树的中序遍历二叉树的后序遍历单值二叉树二叉树最大深度检查两颗树是否相同.翻转二叉树对称二叉树另一颗树的子树 总结 前言 现在我们开始一轮新的自我提升吧&#xff01; 二叉树的题目当然也更有…

【每日一题】34. 在排序数组中查找元素的第一个和最后一个位置

34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣&#xff08;LeetCode&#xff09; 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 […

【LeetCode每日一题合集】2023.9.11-2023.9.17(⭐反悔贪心拓扑排序Floyd)

文章目录 630. 课程表 III解法——反悔贪心⭐⭐⭐⭐⭐ 1462. 课程表 IV⭐解法1——拓扑排序预处理解法2——Floyd算法判断是否存在路径 2596. 检查骑士巡视方案&#xff08;方向模拟&#xff09;1222. 可以攻击国王的皇后&#xff08;方向模拟&#xff09;LCP 50. 宝石补给&…

Java学习之常见易错点总结--第一期

&#x1f495;"不要同情自己&#xff0c;那是卑劣懦夫干的勾当。"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;Java学习之常见易错点总结--第一期 1.什么时候变量不用初始化&#xff1f; 先来看如下代码&#xff1a; public static void main(…

MediaPipe+OpenCV 实现实时手势识别(附Python源码)

MediaPipe官网&#xff1a;https://developers.google.com/mediapipe MediaPipe仓库&#xff1a;https://github.com/google/mediapipe 一、MediaPipe介绍 MediaPipe 是一个由 Google 开发的开源跨平台机器学习框架&#xff0c;用于构建视觉和感知应用程序。它提供了一系列预训…

C#中Visual Studio如何为解决方案设置启动项目

目录 第一种方法:快速选定启动项目的方法1.在解决方案资源管理器中,选择解决方案(最高层节点)2.选择解决方案节点的上下文(右键单击)菜单,然后选择“属性”。 “解决方案属性页”对话框随即显示第二种方法:右击First11或者second11,点击设置启动项目即可Visual Studio…

C++ PrimerPlus 复习 第七章 函数——C++的编程模块(上)

第一章 命令编译链接文件 make文件 第二章 进入c 第三章 处理数据 第四章 复合类型 &#xff08;上&#xff09; 第四章 复合类型 &#xff08;下&#xff09; 第五章 循环和关系表达式 第六章 分支语句和逻辑运算符 第七章 函数——C的编程模块&#xff08;上&#xff…

【红包雨】中间件与环境安装

创建环境 创建专用网络VPC 安全组 创建云服务器 打包部署 2. Java环境 #下载jdk17 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz #安装上传工具 以后使用命令 rz 选中文件进行上传 yum install -y lrzsz#解压 tar -xzvf jdk-17_linux-x64…