c++------类和对象(下)包含了this指针、构造函数、析构函数、拷贝构造等

文章目录

  • 前言
  • 一、this指针
    • 1.1、this指针的引出
    • 1.2、 this指针的特性
  • 二、类的默认的六个构造函数
    • 2.1、构造函数简述
    • 2.2构造函数
  • 三、析构函数
    • 3.1、析构函数引出
    • 3.2、特点:
  • 四、拷贝构造
    • 4.1、引入
    • 4.2、特征:
    • 4.3、默认拷贝构造函数
  • 总结


前言

在本节中,我将给大家介绍我们在学习C++中经常要用到的,this指针、类的六个默认成员函数、运算符重载等相关知识.

下面我会结合一个简单的类----日期类来介绍

后面需要时会补充相应的成员函数

class Date
{
public:
	void Display()//打印类对象中的内容
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

一、this指针

1.1、this指针的引出

int main()
 {
    Date d1, d2;
    d1.SetDate(2024,5,1);
    d2.SetDate(2024,6,1);
    d1.Display();
    d2.Display();
    return 0;
 }

当执行上述代码时,它的输出结果为:
在这里插入图片描述
下面的汇编不了解的,可以搜一下栈帧的创建和销毁,对今后的学习帮助很大
在这里插入图片描述

通过汇编我们可以看到,两次调用的SetDat函数地址相同(调用同一函数)

对于上述类,有这样的一个问题:
Date类中有SetDate与Display两个成员函数,函数体中没有关于不同对象的区分,那当d1调用SetDate函数时,该函数是如何知道应该设置s1对象,而不是设置d2对象呢?

C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

1.2、 this指针的特性

  1. this指针只能在“成员函数”的内部使用
  2. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。
  3. this指针是成员函数第一个隐含的指针形参,不需要用户
    传递.

将调用成员函数展开:
在这里插入图片描述

下面我们来证明一下this指针,本质上就是对象的地址:

为了更清晰的展示,我会简化用不到的代码

class Date
{
public:
	void Print_this()
	{
		cout << this << endl;//打印this指针
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;
	d1.Print_this();//
	cout << &d1 << endl;
	//如果和我们说的一样,那么打印结果应该两两相同
	d2.Print_this();
	cout << &d2 << endl;
	return 0;
}

结果:
在这里插入图片描述
可以看到this本质就是对象的地址。这就是隐藏的this指针,当然我们可以像学习C语言时知道一个结构体对象的地址使用“->”来进行成员变量的访问

class Date
	{
	public:
		void Display()
		{
			cout <<this-> _year << "-" <<this-> _month << "-" << this->_day << endl;
		}
	private:
		int _year; // 年
		int _month; // 月
		int _day; // 日
	};

二、类的默认的六个构造函数

在这里插入图片描述

恩师莫怪

2.1、构造函数简述

如果一个类中什么成员都没有,简称为空类。空类中什么都没有吗?并不是的,任何一个类在我们不写的情况下,编译器都会自动生成6个默认成员函数。这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。
构造函数特点:

1.构造函数的名字和类名相同。
2.和其他函数不一样的是,构造函数没有返回类型。
3.类似于其他的函数,构造函数也有一个(可能为空的)参数列表和一个(可能为空的)函数体。
4.构造函数不能被声明成const 的。

需要特别注意的是,一个类可以拥有多个参数不同的构造函数,这些构造函数之间,向普通函数之间一样,可以构成函数重载

2.2构造函数

再贴一遍方便大家看

class Date
{
public:
	void Display()//打印类对象中的内容
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};

对于Date类,可以通过SetDate公有的方法给对象设置内容,但是如果每次创建对象都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?我们上面说过:创建类的类型对象时由编译器自动调构造函数,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。

class Date
{
public:
    // 1.无参构造函数
    Date()
    {}
    // 2.带参构造函数
    Date(int year, int month, int day)//无返回值
    {
        _year = year;
        _month = month;
        _day = day;
    }
private:
    int _year;
    int _month;
    int _day;
};
void TestDate()
{
    Date d1; // 调用无参构造函数
    Date d2(2024, 6, 1); // 调用带参的构造函数,用于初始化
    // 注意:如果通过无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明
    // 以下代码的函数:声明了d3函数,该函数无参,返回一个日期类型的对象
    Date d3();

如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
1.证明编译器默认生成的为无参的构造函数:

在这里插入图片描述

可以看到,我将自己写的构造函数屏蔽后,调用有参的构造函数是无法成功的,无参的并没有报错,这也说明编译器默认生成的为无参的构造函数。
2.证明当我们显示写出一个构造函数,编译器就不会在生成默认的构造函数:
在这里插入图片描述

我将带参的构造函数显示定义,d1无法调用无参的默认构造函数。
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且这两个默认构造函数不能同时存在。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认成员函数.

默认构造函数我们一般是为了处理自定义类型的成员变量

三、析构函数

3.1、析构函数引出

前面通过构造函数的学习,我们知道一个对象时怎么来的,那一个对象又是怎么没呢的?
析构函数:与构造函数功能相反,析构函数不是完成对象的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成类的一些资源清理工作(比如:类中定义的指针指向的空间的清理)

3.2、特点:

  1. 析构函数名是在类名前加上字符 ’~‘。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
![class Date
{
public:
    ~Date()
    {
        _year = 0;
        _month = 0;
        _day = 0;
    } 
    Date(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }
    int _year;
    int _month;
    int _day;
};
int main()
{
    Date d2(2024, 6, 1);
    return 0;
}

反汇编视角:
在这里插入图片描述

在上面的代码中,我并没有去显示调用析构函数,但是在程序执行结束时,编译器自动调用了,析构函数
这个也可以像构造函数一样测试,大家尝试一下

四、拷贝构造

4.1、引入

拷贝构造函数是构造函数的一种重载形式,它可以用来创建一个与已存在的对象一模一样的新对象。对于拷贝构造,它只有单个形参,且该形参必须是对本类类型对象的引用,因为要引用,所以要加const修饰。

4.2、特征:

1.拷贝构造函数的参数若使用传值方式编译器直接报错, 因为会引发无穷递归调用
2.若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数,对对象按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
3.编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了。

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)//全缺省
 {
 _year = year;
 _month = month;
 _day = day;
 }
 // Date(const Date d)   // 错误--引发无穷递归
    Date(const Date& d)   // 正确写法
 _year = d._year;
 _month = d._month;
 _day = d._day;
 }
private:
 int _year;
 int _month;
 int _day;
};
int main()
{
 Date d1;
 Date d2(d1);//也可以写成Date d2=d1
 return 0;
}

4.3、默认拷贝构造函数

像上面介绍的默认成员函数一样,当我们没有在类中写拷贝构造函数时,编译器会自动生成一个默认的拷贝构造。

系统生成的拷贝构造也会针对成员变量的内置类型和自定义类型做一个区分。对于内置类型的成员变量,编译器会按照被拷贝对象的内存存储字节序完成拷贝,就好比被拷贝的对象有3个int类型成员变量,占12字节内存,编译器会根据该对象的内存和成员初始值拷贝给新对象。

总结

本次我们介绍了,this指针、构造函数、析构函数、拷贝构造、等一些与类紧密关联的知识。
要将他们详细的介绍,所用篇幅过长,后续会出拓展版的

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

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

相关文章

LeetCode-77. 组合【回溯】

LeetCode-77. 组合【回溯】 题目描述&#xff1a;解题思路一&#xff1a;回溯背诵版解题思路三&#xff1a;0 题目描述&#xff1a; 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&a…

从tensorflow导入EarlyStopping能运行但是一直提示未解析

在pycharm中导入早停机的库时&#xff0c;碰上一个问题 from tensorflow.keras.callbacks import EarlyStopping这一条代码中&#xff0c;EarlyStopping一直有个红色波浪线&#xff0c;代表着找不到这个库&#xff0c;提示未解析啥的。 但是运行是可以运行的&#xff0c;虽然可…

禁用手机连接 - Win11

问题 Win11系统自带手机连接软件&#xff0c;会在后台自启&#xff0c;不适用于全部的手机型号&#xff0c;而且常规方法无法卸载。甚至任务管理器中&#xff0c;此软件的后台进程高达76个&#xff0c;如下图。下文以Win11系统为例&#xff0c;介绍如何禁用手机连接。 解决方…

【Unity脚本】修改游戏对象的活动状态

【知识链】Unity -> Unity脚本 -> 游戏对象 -> 活动状态【摘要】本文介绍了如何通过编辑器和脚本来访问游戏对象的活动状态&#xff0c;并给出具体的场景示例。 文章目录 第一章 引言第二章 在编辑器中设置活动状态2.1. 在编辑器中设置活动状态2.1.1. 停用游戏对象2.…

JVM学习笔记(持续更新)

JDK、JRE、JVM区别&#xff1f; 类加载过程 装载 验证 准备 解析 初始化 类加载器分类 双亲委派模型 如何打破双亲委派模型&#xff1f; 自定义类加载器&#xff0c;集成ClassLoader类重写loadClass,如Tomcat JVM内存模型 JVM 需要使用计算机的内存&#xff0c;Java 程序…

文件批量改后缀名,轻松实现TXT到DOCX格式转换,高效管理您的文件库!

文件处理与管理已成为我们日常生活和工作中不可或缺的一环。然而&#xff0c;面对海量的文件&#xff0c;如何高效地进行格式转换和管理&#xff0c;却成为了一道难题。今天&#xff0c;我们将为您揭晓一个神奇的解决方案——文件批量改后缀名功能&#xff0c;让您轻松实现TXT到…

2024/6/2 英语每日一段

However, they denied Hirst had been deliberately misleading, arguing that it was his “usual practice” to date physical works in a conceptual art project with the date of the project’s conception, which in the case of The Currency was 2016. Hirst and Sci…

AI大模型探索之路-实战篇13: 从对话到报告:打造能记录和分析的Agent智能数据分析平台

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

外卖点餐系统 springboot+vue+element-ui

免费获取方式↓↓↓ 项目介绍038&#xff1a; http://localhost:8080/ 账号&#xff1a;weiguanke 123 系统登陆后展示 用户可视界面 – 登录页面 – 首页&#xff1a; – 店铺查找页面&#xff1a; 店铺查找 – 店铺页面 店铺管理者可视页面 – 店铺页面 店铺管理员…

十大排序 —— 归并排序

十大排序 —— 归并排序 归并排序分治(排序)合归并排序的性能一些小总结 我们今天继续来学习排序算法 —— 归并排序: 归并排序 归并排序&#xff08;Merge Sort&#xff09;是一种高效的、稳定的排序算法&#xff0c;它采用分治法&#xff08;Divide and Conquer&#xff09…

Spring原理-IOC和AOP

概述 在此记录spring的学习内容。spring官网&#xff1a;https://spring.io/ 概念故事 从前&#xff0c;在Java的大森林中&#xff0c;有一片神奇的土地&#xff0c;名叫"Spring"。这片土地上生长着各种美丽而强大的植物&#xff0c;它们分别象征着Spring框架中的…

LabVIEW调用第三方硬件DLL常见问题及开发流程

在LabVIEW中调用第三方硬件DLL时&#xff0c;除了技术问题&#xff0c;还涉及开发流程、资料获取及与厂家的沟通协调。常见问题包括函数接口不兼容、数据类型转换错误、内存管理问题、线程安全性等。解决这些问题需确保函数声明准确、数据类型匹配、正确的内存管理及线程保护。…

金钱世界:资本主义的未来

概述 《金钱世界&#xff1a;资本主义的未来》是一部探讨资本主义未来、全球经济停滞、大型全球企业与国家关系以及贫富差距问题的纪录片。纪录片分集内容&#xff1a;该纪录片共分为3集&#xff0c;每集都聚焦于不同的主题&#xff1a; 第一集《世界会继续发展吗&#xff1f…

QT实现动态翻译切换

1、实现QT动态中英文切换效果 效果如下: 2、原理 因为软件本身就是中文版,所以只需准备一个英文版的翻译即可,,那就是将所有需要翻译的地方用tr包裹,然后首先执行lupdate更新一下,接着用qt的翻译软件 Qt Linguist打开ts文件进行翻译,然后保存,最后使用 lrelease发布一…

小白跟做江科大32单片机之旋转编码器计次

原理部分按照下面这个链接理解即可y小白跟做江科大32单片机之对射式红外传感器计次-CSDN博客https://blog.csdn.net/weixin_58051657/article/details/139350487https://blog.csdn.net/weixin_58051657/article/details/139350487 实验过程 1.按照江科大老师给的电路图进行连接…

音视频开发—V4L2介绍,FFmpeg 打开摄像头输出yuv文件

实验平台&#xff1a;Ubuntu20.04 摄像头&#xff1a;1080P 监控摄像头&#xff0c;采用V4L2驱动框架 文章目录 1.V4L2相关介绍1.1. 基本概念1.2. 主要功能1.3. V4L2驱动框架1.4. 主要组件1.5. 使用V4L2的应用1.6. 常用V4L2工具 2.ffmpeg命令实现打开摄像头输出yuv文件3.使用C…

文献阅读:GCNG:用于从空间转录组数据推断基因相互作用的图卷积网络

文献介绍 「文献题目」 GCNG: graph convolutional networks for inferring gene interaction from spatial transcriptomics data 「研究团队」 Ziv Bar-Joseph&#xff08;美国卡内基梅隆大学&#xff09; 「发表时间」 2020-12-10 「发表期刊」 Genome Biology 「影响因子…

一文搞懂分布式事务Seta-AT模式实现原理

分布式事务概念 分布式事务&#xff08;Distributed Transaction&#xff09; 是指在分布式系统中&#xff0c;涉及多个数据库、服务、消息队列等资源&#xff0c;并且需要保证这些资源上的操作要么全部成功提交&#xff0c;要么全部失败回滚的一种机制。在分布式系统中&#…

极简网络用户手册(1)

极简网络系统处理流程 模块位置&#xff1a;参数平台--专题分析--极简网络分析 步骤&#xff1a; 步骤一&#xff1a;创建精细化场景策略 步骤二&#xff1a;创建任务&#xff0c;主要选择策略&#xff08;包括√配置和距离配置&#xff09;和需要处理的小区清单&#xff08;源…

vulhub中Nexus Repository Manager 3 未授权目录穿越漏洞(CVE-2024-4956)

Nexus Repository Manager 3 是一款软件仓库&#xff0c;可以用来存储和分发Maven、NuGET等软件源仓库。 其3.68.0及之前版本中&#xff0c;存在一处目录穿越漏洞。攻击者可以利用该漏洞读取服务器上任意文件。 环境启动后&#xff0c;访问http://your-ip:8081即可看到Nexus的…