C++初阶之类与对象(中)——六个默认函数详细解析

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶    

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.前言

二.构造函数

2.1构造函数的语法和特性

2.1.1语法

2.1.2特性

2.2代码演示与验证

2.2.1构造函数的多种写法(语法部分验证)

2.2.1.1无参

2.2.1.2传参数

2.2.1.3全缺省 

2.2.1.4默认生成

2.2.1.5三种只能存在一种

2.2.2类嵌套类(特性部分验证)

2.3C++11新写法

三.析构函数

3.1析构函数的语法

3.2代码演示与验证

3.3析构函数应用场景

3.4析构函数的调用顺序

四.拷贝构造

4.1特性

4.2代码解析

4.2.1只有一个拷贝后构造的日期类出现的问题

4.2.2正确的代码

4.3深拷贝

4.4解决方案

4.5传值引发的死递归

五.总结



一.前言

        在本次博客中我将给大家带来6个默认成员函数,主要包括构造函数,析构函数,拷贝构造,赋值重载,符号重载,在这次文章中我们需要记住一个关键点自动调用,其中构造函数是对数据进行初始化,析构函数是完成清理工作,拷贝构造是对同同类对象进行初始化 ,赋值重载是把一个对象给另一个对象。其中重要的是前四个,我们这次对前三个进行讲解。

二.构造函数

2.1构造函数的语法和特性

2.1.1语法

  • 构造函数函数名和类名相同。
  • 构造函数支持函数重载。
  • 构造函数无返回值。
  • 构造函数在对象实例化的时候自动调用。   

2.1.2特性

  • C++分为内置类型和自定义类型,内置类型不会处理,定义类型自动调用它的默认构造。
  • 如果我们没有写默认构造编译器会自动生成一个默认构造。
  • 默认构造会自动调用,其中默认构造包括无参形式,全缺省形式以及编译器自动生成的默认构造,这三个只能存在一个。

2.2代码演示与验证

2.2.1构造函数的多种写法(语法部分验证)

2.2.1.1无参

我们分文件进行编写,我们先创建一个类,头文件的代码为:

#pragma once
#include<iostream>
using namespace std;class Data {
public:Data(){_year = 1;_month = 1;_day = 1;}void Print();
private:int _year;int _month;int _day;
};

我们的打印函数在另一个.cpp文件,主函数在另外一个.cpp文件中

#include"class.h"void Data::Print()
{cout << _year << "/" << _month << "/" << _day << endl;
}

主函数的代码为:

#include"class.h"int main()
{Data d1;d1.Print();return 0;
}

我们运行代码就会看到d1的年月日都被初始化为1

2.2.1.2传参数

我们将构造函数改为

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

我们按照上面的代码继续运行就会出现问题:

编译器显示我们没有默认构造函数可用,这是为什么呢?我们不是写了吗?我们写了,所以编译器不会生成,只能选择我们写的,我们需要对其进行传参,那我们应该如何修改呢?我们需要知道构造函数时什么时候调用的呢?构造函数是在生成实例化对象的时候自动调用的,所以我们在生成实例化对象的时候进行传参,

//Data d1;
Data d1(1, 1, 1);

看到这里有人就会想到为什么无参的为什么不写成Data da();这主要就是为了和我们的函数声明区分开

2.2.1.3全缺省 
	Data(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}

我们将构造函数改成全缺省的形式,的那我们在生成实例化对象的时候既可以传参也可以不传参

	Data d1(1, 1, 1);Data d2;

这两种都可以使用。

2.2.1.4默认生成

我们不写构造函数,我们的结果是什么样子的呢?

我们看大是这些是,这是由于编译器的不同,所以数据可能不同。

2.2.1.5三种只能存在一种

        如果我们写了构造函数,编译器不会生成构造函数,也就是说编译器生成的构造函数和我们写的不能共存,这一点是非常容易理解的,对于无参和全缺省的我们可以看下面的示例:

我们的构造函数为:

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

我们的测试代码为:

Data d2;

我们可以看到错误为:

这是因为我们的测试代码对于这两种都符合,编译器不知道运行哪一个,所以我们的无参和构造函数不能同时存在,传参数的和无参的虽热可以同时存在,但是他们两个的功能一个全缺省就可以解决,所以全缺省是最完美的。

2.2.2类嵌套类(特性部分验证)

我们将类进行修改,并且增加一个新的类:

class A {
public:A(int data1=1, int data2=1){_data1 = data1;_data2 = data2;}
private:int _data1;int _data2;
};
class Data {
public:int num;Data(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}	void Print();
private:int _year;int _month;int _day;A _a;
};

我们进行调试就可以看到我们的内置类型不做任何处理,也就是我们的d2.num,内置类型会调用它的默认构造。

2.3C++11新写法

        在C++11中委员会对构造函数进行了新的更新,可以在声明时进行缺省,我们看下面的代码样例:

class Data {
public:	void Print();
private:int _year=2;int _month = 2;int _day=2;};

三.析构函数

3.1析构函数的语法

  • 析构函数函数名是~类名
  • 析构函数不支持函数重载
  • 析构函数无参数无返回值
  • 对象的声明周期结束时自动调用,若没用显示定义编译器会自动生成。

3.2代码演示与验证

        我们在类里面加上我们析构函数(析构函数是对没用用的资源进行处理,由于我们写的是日期类,不用进行资源的清理,并且为了我们为了更详细的演示所以我们进行打印函数名)。

class Data {
public:Data(int year = 1, int month = 1, int day = 1){cout << "Data" << endl;}~Data(){cout << "~Data" << endl;}
private:int _year;int _month;int _day;};

我们运行后可以看到:

3.3析构函数应用场景

        说到我们的析构函数,我们应该知道祖师爷为什么设计出我们的析构函数,你是否有这样的经历,一个软件本来是挺快的但是当我们用了一段时间后就会变得很卡,当我们将后台杀了再打开就会变快,但是用一段时间后又会卡,这主要就是一些文件打开后就没有关闭,再我们下写程序的时候我们总会出现这样的情况开辟了一段空间后总会忘记释放,祖师爷也深受这些的困扰,所以出现了我们的析构函数,我们一个应用场景就是栈,我们写一个类,代码如下:

class Stack {
public:Stack(){_a = new int[4];_size = 0;_capacity = 4;}~Stack(){delete _a;}
private:int* _a;int _size;int _capacity;
};

在这里就是我们对析构函数的一个应用。

3.4析构函数的调用顺序

我们看下面代码:

Data d4(4, 4, 4);
Data d5(5, 5, 5);
int main()
{Data d1(1, 1, 1);static Data d2(2, 2, 2);Data d3(3, 3, 3);return 0;
}

我们需要知道我们的析构函数符合栈的规则,符合后进先出,也就是说我们先调用后面的析构函数,我们运行后可以看到:

符合我们的规则,先析构3再析构1,由于2是静态变量所以后出,出2,然后出我们的全局变量,出5再出4;我们将5和4定义的位置互换

Data d5(5, 5, 5);
Data d4(4, 4, 4);int main()
{Data d1(1, 1, 1);static Data d2(2, 2, 2);Data d3(3, 3, 3);return 0;
}

我们运行后可以看到:

四.拷贝构造

4.1特性

  • 拷贝构造是构造函数的重载
  • 拷贝构造在传址或传参时自动调用
  • 拷贝构造只有一个参数,必须是类的对象,传值时会发生错误出现死递归,所以我们采用引用。
  • 如果没有显式定义,编译器会自动生成浅拷贝的拷贝构造,如果需要深拷贝就不能完成。

4.2代码解析

4.2.1只有一个拷贝后构造的日期类出现的问题

class Data {
public:Data(const Data& d){_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;};

当我们运行

	Data d1;

我们看到的错误信息为

这时候我们想构造函数不是默认生成的吗?怎末会不存在默认构造?仔细看我们类的定义,你会发现我们拷贝构造的构造函数重载了,我们需要知道拷贝构造也是构造,所以我们在写拷贝构造时我们需要加上我们的构造函数。

4.2.2正确的代码

class Data {
public:Data(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Data(const Data& d){_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;};

我们需要将拷贝构造和构造函数一块写,我们只写拷贝构造的话编译器也不会生成构造函数,这是因为拷贝构造也是构造

4.3深拷贝

        在上面的拷贝都是一些浅拷贝,我们看下面的代码:

class Stack {
public:Stack(int capacity=4){_a = new int[4];_size = 0;_capacity = capacity;}~Stack(){delete[] _a;}Stack(const Stack& s){_a = s._a;_size = s._size;_capacity = s._capacity;}
private:int* _a;int _size;int _capacity;
};

我们运行的代码为:

	Stack s1(4);Stack s2(s1);

我们运行后可以看到:

这个主要就是程序出现了对空间的二次free。

4.4解决方案

我们只需要对拷贝构造进行修改即可:

	Stack(const Stack& s){int * _tmp = new int[4];_size = s._size;_capacity = s._capacity;memcpy(_tmp, s._a, 16);_a = _tmp;}

4.5传值引发的死递归

	Data( const Data d){_year = d._year;_month = d._month;_day = d._day;}

这是我们的拷贝构造,我们需要知道当我们调用拷贝构造时会自动调用一次拷贝构造,也就是说传自定义类型时会调用拷贝构造,由于我们使用的是传值,这次调用,调用的会再次调用拷贝构造, 这样就会发生死递归,当我们改成传引用就会完美的解决我们的问题。

五.总结

        类是我们C++中的一个重点,大家可以多看看,最后希望大家可以一键三连。

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

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

相关文章

Blender教程(基础)-顶点合并-18

一、常规合并 准备&#xff0c;新建一个圆环8个点、全选顶点采用F填充&#xff0c;采用J链接多个顶点如下图所示图形。 选择其中一个顶点 按字母GG、移动到离另外一个顶点更近。再选中两个顶点&#xff0c;右键弹出合并顶点>到中心 二、重叠合并 回退回去 按字母G…

LocalAI 部署(主要针对 mac m2 启动)

LocalAI 部署 介绍 LocalAI 是免费的开源 OpenAI 替代方案。 LocalAI 充当 REST API 的直接替代品&#xff0c;与本地推理的 OpenAI API 规范兼容。 它无需 GPU&#xff0c;还有多种用途集成&#xff0c;允许您使用消费级硬件在本地或本地运行 LLM、生成图像、音频等等&#…

第二节:轻松玩转书生·浦语大模型趣味Demo

参考教程&#xff1a;https://github.com/InternLM/tutorial/blob/main/helloworld/hello_world.md InternLM-Chat-7B 智能对话 Demo 终端运行 web demo 运行 1.首先启动服务&#xff1a; cd /root/code/InternLM streamlit run web_demo.py --server.address 127.0.0.1 --…

普京警告:美元大衰落

来源&#xff1a;Bitcoin.com 编译/作者&#xff1a;秦晋 美元不仅是全球储备货币&#xff0c;也是美国用来维护全球权力的重要武器。甚至还是衡量比特币市值与价格的重要指标之一。比特币富豪的财富指标某种程度上也是通过美元多少来进行衡量的。 2月9日&#xff0c;俄罗斯总统…

(免费领源码)java+SSM+mysql 大学食堂订餐系统APP 75418-计算机毕业设计项目选题推荐

摘 要 本论文主要论述了如何使用SSM框架开发一个大学食堂订餐系统APP&#xff0c;将严格按照软件开发流程进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述大学食堂订餐系统APP的当前背景以及系统开发的目的&#xff0c;后续章节将…

一、Docker部署MySQL

Docker部署MySQL 一、安装Docker二、拉取MySQL镜像1.选择拉取版本2.拉取镜像 三、启动MySQL1.确定好挂载目录2.启动3.查看是否启动4.开启远程访问权限 一、安装Docker 安装教程&#xff1a;https://qingsi.blog.csdn.net/article/details/131270071 二、拉取MySQL镜像 1.选择…

双指针练习题复写零

复写零 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改&#xff0c;不要从函数返回任何东西。 示例 1&…

【JavaEE进阶】 利用Spring简单实现加法计算器和用户登录

文章目录 &#x1f38d;序言&#x1f333;加法计算器&#x1f6a9;准备工作&#x1f6a9;约定前后端交互接⼝&#x1f332;后端服务器代码的书写 &#x1f334;用户登录&#x1f6a9;效果展示&#x1f6a9;准备工作&#x1f6a9;约定前后端交互接⼝&#x1f388;需求分析&#…

JavaI/O流 File类(目录)

目录 File类目录操作实例 File类目录操作 Java的File类提供了对文件和目录进行操作的方法。对于目录&#xff0c;File类提供了以下一些方法&#xff1a; 判断目录是否存在&#xff1a;使用exists()方法可以判断目录是否存在。创建目录&#xff1a;使用mkdir()或mkdirs()方法可…

16 贪吃蛇

目录 游戏背景游戏效果展示基本功能技术要点WIN32 API介绍设计与分析实现参考代码 1. 游戏背景 贪吃蛇是久负盛名的游戏&#xff0c;是一款经典游戏 2. 效果展示 3. 基本功能 使用c语言在windows环境的控制台模拟实现小游戏贪吃蛇 基本的功能&#xff1a; 地图绘制吃食物上…

MIT-Missing Semester_Topic 3:Editors (Vim) 练习题

文章目录 练习一练习二练习三练习四练习五练习六练习七练习八 本 Topic 的 MIT 讲解网页&#xff08;练习题未给解答&#xff09; 练习一 自行完成 vimtutor。vimtutor 是 Vim 本身附带的一个入门教程&#xff0c;在 shell 中直接输入 vimtutor 便能运行。注意该教程在 8024 大…

【小沐学GIS】基于C++QT绘制三维数字地球Earth(OpenGL)

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;456:OpenGL、glfw、glut&#xff09;第二期3【小沐…

QT:实现图片选择器

一、效果图 二、用到的类 qApp&#xff1a;可以快速获取到项目目录位置。 QSettings &#xff1a;编写config文件&#xff0c;记录上次打开图片的位置&#xff0c;下次打开图片会从上次的位置查找图片。 QPixmap&#xff1a;用于图片的缩放&#xff0c;防止图片过小&#xff0…

DVWA靶场下载安装

DVWA介绍 DVWA 一共包含了十个攻击模块&#xff0c;分别是:Brute Force(暴力破解)、Command Injection(命令行注入)、CSRF(跨站请求伪造)、File Inclusion(文件包含)、File Upload(文件上传)、Insecure CAPTCHA (不安全的验证码)、SQL Injection(SQL注入)、SQL Injection Blin…

【Java程序设计】【C00249】基于Springboot的私人健身与教练预约管理系统(有论文)

基于Springboot的私人健身与教练预约管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的私人健身与教练预约管理系统 本系统分为系统功能模块、管理员功能模块、教练功能模块以及用户功能模块。 系统功能模…

一、部署Oracle

部署Oracle 一、Docker部署1.Oracle11g1.1 测试环境1.1.1 拉取镜像1.1.2 启动容器1.1.3 配置容器环境变量1.1.4 修改sys、system用户密码1.1.5 创建表空间1.1.6 创建用户并授权1.1.5 使用DBeaver测试连接 二、安装包部署 一、Docker部署 1.Oracle11g 1.1 测试环境 当前只能用…

【Spring MVC篇】Cookie和Session的获取 Header的获取

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【Spring MVC】 本专栏旨在分享学习Spring MVC的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; Cookie是客户端保存用…

基于Java (spring-boot)的职工管理系统

一、项目介绍 基于Java (spring-boot)的职工管理系统功能&#xff1a;登录、老板、职员人事经理、职员、部门列表、职工列表、权限修改、查看所有管理、正在审核列表、添加考勤、添加职工、添加奖惩、合同列表、合同信息、等等等。 适用人群&#xff1a;适合小白、大学生、毕业…

360网络安全面试题汇总

防范常见的 Web 攻击 重要协议分布层 arp 协议的工作原理 rip 协议是什么&#xff1f;rip 的工作原理 什么是 RARP&#xff1f;工作原理 OSPF 协议&#xff1f;OSPF 的工作原理 TCP 与 UDP 区别总结 什么是三次握手四次挥手&#xff1f; tcp 为什么要三次握手&#xff1f; dns…

Science重磅_让大模型像婴儿一样学习语言

英文名称: Grounded language acquisition through the eyes and ears of a single child 中文名称: 通过一个孩子的眼睛和耳朵基于实践学习语言 文章: https://www.science.org/doi/10.1126/science.adi1374 代码: https://github.com/wkvong/multimodalbaby 作者: Wai Keen V…