C++从零到满绩——类和对象(中)

news2024/11/25 10:49:00

 

目录

1>>前言

2>>构造函数(我称之为初始化函数)

3>>析构函数(我称之为销毁函数)

4>>拷贝构造函数(我称之为复制函数)

 5>>运算符重载

5.2>>赋值运算符重载

​编辑

6>>结语

1>>前言

        上节课学习了基础篇(包括函数重载、引用、inline、nullptr)and类和对象(上)(包括类的定义、实例化、this指针),忘记的宝子们可以去复习一下~~~

枫の大一-CSDN博客C++从零到满绩——入门基础and类和对象(上)-CSDN博客  跳转上篇

枫の大一-CSDN博客  跳转个人主页查看

        今天我们来类和对象(中)(包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载)。需要注意的是今天我们学习的四个内容 始终 带着两个疑问:

第一:我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求?

第二:编译器默认生成的函数不满足我们的需求,我们需要自己实现,那么如何自己实现?

ps:如果有觉得小编哪里需要改进的欢迎指出,做出完美的C++篇章肯定少不了各位精神股东的支持啦,谢谢大家~

2>>构造函数(我称之为初始化函数)

        构造函数虽然有构造二字,但它并非开空间造对象,而是在对象实例化时初始化对象。它的本质就是替代之前写的init初始化函数,并且它还能自动调用,简直perfect!

构造函数的特点:

1.函数名域类名一样。

2.无返回值。没有void!!!

3.对象实例化时会自动调用。

4.构造函数可重载。

5.如果类中没有显式定义(我们自己写的)构造函数,编译器会自动生成无参默认构造函数。

6.默认构造包括:无参构造函数、全缺省构造函数、编译器默认生成的构造函数。简单说就是不需要我们传实参就是默认构造。

7.编译器默认生成的构造函数,对于内置类型初始化不确定,看编译器;对于自定义类型成员变量,要求调用这个成员变量的默认构造函数进行初始化。类似于高数的链式求导,y不能对x求导,可以对t求导,t在对x求导。

#include<iostream>
using namespace std;
class Date {
public://公共
	void print() {//打印函数
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private://私有
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1;
	d1.print();
	return 0;
}

 不写构造函数运行结果为随机值

#include<iostream>
using namespace std;
class Date {
public://公共
	Date(int year = 1, int month = 1, int day = 1) {//构造函数
		_year = year;
		_month = month;
		_day = day;
	}
	void print() {//打印函数
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private://私有
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1(2024, 11, 24);
	d1.print();
	return 0;
}

写了构造函数对变量d1进行了初始化操作,还用到了上节课的缺省参数 

 

d1这里后面什么都不写

Date d1;

运行结果为1/1/1,因为缺省参数帮助初始化了。 

 

可以发现我们没有进行调用,而是在实质化对象的时候自动调用,这就是它的好用之处。这就是构造函数的使用。

3>>析构函数(我称之为销毁函数)

        析构函数功能与构造函数相反,听名字可以理解为解析构造,将构造函数一步步剖析。它的工作是完成对象中资源的清理释放工作。类似与之前栈使用的Destroy功能。

析构函数的特点:

1.析构函数名是在类名前加上字符~。~本身也是按位取反的意思,这里代表相反。

2.无参数无返回值。不需要void!!!

3.一个类只能有一个析构函数。

4.对象生命周期结束时,系统会自动调用析构函数。

5. 自定义类型的成员变量都会调用析构函数(不管是写的还是默认生成的)。

6.若类无申请资源,析构可以不写,如Date;若类都是自定义成员变量,它们都有自己的析构,也可以不写,如用两个栈实现队列的MyQueue;若有申请资源,一定要写,如用两个栈实现队列的Stack。

7.若有多个对象,后定义的先析构。

#include<iostream>
using namespace std;
typedef int StDataType;
class Stack {
public://公共
	Stack(int n=4) {//构造函数
		_arr = (StDataType*)malloc(sizeof(StDataType) * n);
		if (nullptr == _arr)
		{
			perror("malloc获取失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}
	
	~Stack() {//析构函数
		free(_arr);
		_arr = nullptr;
		_capacity = _top = 0;
	}
private://私有
	StDataType* _arr;
	int _capacity;
	int _top;
};
int main() {
	Stack st;
	return 0;
}

4>>拷贝构造函数(我称之为复制函数)

        拷贝构造函数第一个参数时自身类型的引用,其他参数都是缺省参数。

拷贝构造的特点:

1.拷贝构造函数是构造函数的重载。

2.拷贝构造参数第一个必须是自身类型的引用。

3.自定义类型对象进行拷贝时必须调用拷贝构造,因此传值传参和传值返回的行为都会调用拷贝构造。

4.若未自己写,编译器会自动生成。自动生成的拷贝构造是值拷贝/浅拷贝(一个字节一个字节拷贝),自定义成员变量会调用它的拷贝构造。

5.需要我们写析构的也要写拷贝构造,例如Stack。因为它有申请资源,浅拷贝会导致两块st1和st2都指向同一块空间,因此要进行深拷贝,所以要自己写。

6.传值返回会调用拷贝构造,传值“引用”返回没产生拷贝,因此不需要调用。但是如果返回的引用时一个局部对象,在函数结束时销毁,那么引用会变成野引用,那就不行。传引用返回前提是函数结束后还在。

#include<iostream>
using namespace std;
class Date {
public://公共
	Date(int year = 1, int month = 1, int day = 1) {//构造函数
		_year = year;
		_month = month;
		_day = day;
	}
	void print() {//打印函数
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private://私有
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1(2024,11,24);
	Date d2(d1);
	d1.print();
	d2.print();
	return 0;
}

 

 用栈的拷贝构造:

//拷贝构造
#include<iostream>
using namespace std;
typedef int StDataType;
class Stack {
public://公共
	Stack(int n = 4) {//构造函数
		_arr = (StDataType*)malloc(sizeof(StDataType) * n);
		if (nullptr == _arr)
		{
			perror("malloc获取失败");
			return;
		}
		_capacity = n;
		_top = 0;
	}

	Stack(const Stack& source) {//拷贝构造函数
		//需要再开辟一个同样大小空间
		_arr = (StDataType*)malloc(sizeof(StDataType) * source._capacity);//乘上之前空间大小
		if (nullptr == _arr)
		{
			perror("malloc获取失败");
			return;
		}
		memcpy(_arr, source._arr, sizeof(StDataType) * source._top);//复制有效数据
		_capacity = source._capacity;
		_top = source._top;
	}

	~Stack() {//析构函数
		free(_arr);
		_arr = nullptr;
		_capacity = _top = 0;
	}
private://私有
	StDataType* _arr;
	int _capacity;
	int _top;
};
int main() {
	Stack st;
	Stack st2(st);
	return 0;
}

 5>>运算符重载

1.这里重载和之前的函数重载区分开,并不是一个意思。

2.当两个类类型对象进行运算符操作时,不能直接操作,需要我们写一个对应的运算符重载函数才可以。

3.它由operator和定义的运算符构成。

4.它的参数个数和运算对象一样多。

5.如果一个重载运算符函数是成员函数,那它少一个参数,因为有隐藏的this指针。

6.特别注意5个运算符不能重载:(.*  ::  sizeof  :?  .)

7.至少有一个类类型参数。

//运算符重载
#include<iostream>
using namespace std;
class Date {
public://公共
	Date(int year = 1, int month = 1, int day = 1) {//构造函数
		_year = year;
		_month = month;
		_day = day;
	}

	bool operator==(const Date& d2) {//重载格式:operator符号
		return _year == d2._year
			&& _month == d2._month
			&& _day == d2._day;
	}
	void print() {//打印函数
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private://私有
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1(2024,11,24);
	Date d2(d1);
	int r= d1 == d2;
	cout << r;
	return 0;
}

5.2>>赋值运算符重载

        跟拷贝构造区分开,它是两个已经存在的对象进行赋值。

赋值运算符重载特点:

1.必须重载为成员函数,建议带上const。

2.有返回值,写当前类类型的引用,提高效率。

 

//赋值运算符重载
#include<iostream>
using namespace std;
class Date {
public://公共
	Date(int year = 1, int month = 1, int day = 1) {//构造函数
		_year = year;
		_month = month;
		_day = day;
	}

	Date& operator=(const Date& d2) {//重载格式:operator符号
		//跳过自己给自己赋值
		if (this != &d2) {
			_year = d2._year;
			_month = d2._month;
			_day = d2._day;
		}
		//因为d1=d2返回的是d1,而*this也是d1,所以返回*this
		return *this;
	}
	void print() {//打印函数
		cout << _year << "/" << _month << "/" << _day << endl;
	}
private://私有
	int _year;
	int _month;
	int _day;
};
int main() {
	Date d1(2024, 11, 24);
	Date d2(2024, 11, 299);
	d1 = d2;
	d1.print();
	d2.print();
	return 0;
}

6>>结语

        今日份C++入门就先到这里啦,来总结一下:主要讲了类和对象(中)(包括:构造函数、析构函数、拷贝构造函数、赋值运算符重载),感兴趣的宝子们欢迎持续订阅小编,小编在这里谢谢宝子们啦~C++的学习很陡,时而巨难时而巨简单,希望宝子和小编一起坚持下去~你们的三连是我的动力,感谢支持~

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

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

相关文章

oracle 12c查看执行过的sql及当前正在执行的sql

V$SQL 提供了已经执行过及正在执行的SQL语句的信息。 一 查看共享池中所有sql的统计信息 #统计共享池中某类sql执行次数&#xff0c;总体执行时长&#xff0c;平均执行时长等信息&#xff0c;并按总体执行时长降序排序 SELECT INST_ID,SQL_ID,SQL_TEXT,SQL_FULLTEXT,EXECUTI…

解锁PPTist的全新体验:Windows系统环境下本地部署与远程访问

文章目录 前言1. 本地安装PPTist2. PPTist 使用介绍3. 安装Cpolar内网穿透4. 配置公网地址5. 配置固定公网地址 前言 在Windows系统环境中&#xff0c;如何本地部署开源在线演示文稿应用PPTist&#xff0c;并实现远程访问&#xff1f;本文将为您提供详细的部署和配置指南。 P…

C语言中的指针和字符串的赋值

前言&#xff1a;温习下以前学过的C语言知识&#xff0c;温故而知新。 实例说明 本文用一段实例代码阐述指针和字符串的联系。 #include <iostream> #include <cstring> int main() {using namespace std;char animal[20] "bear";const char * bird …

Linux高阶——1117—TCP客户端服务端

目录 1、sock.h socket常用函数 网络初始化函数 首次响应函数 测试IO处理函数 获取时间函数 总代码 2、sock.c SOCKET() ACCEPT()——服务端使用这个函数等待客户端连接 CONNECT()——客户端使用这个函数连接服务端 BIND()——一般只有服务端使用 LISTEN()——服务端…

物体网格弹性变形---Unity中实现

在游戏引擎场景中的3D物体是由一定数量的点、面组成的&#xff0c;如下图&#xff1a; 要使这些物体变形就是改变3D物体每个顶点状态。 1.首先在Unity场景中增加一个球体&#xff0c;如下图 3D组件默认拥有MeshFilter、meshRenderer、Collider组件&#xff0c;分别用来获取Mes…

【ArcGISPro】根据yaml构建原始Pro的conda环境

使用场景 我们不小心把原始arcgispro-py3的conda环境破坏了,我们就可以使用以下方法进行修复 查找文件 在arcgis目录下找到yaml文件 如果没找到请复制以下内容到新的yaml文件 channels: - esri - defaults dependencies: - anyio=4.2.0=py311haa95532_0 - appdirs=1.4.4=p…

【Y20030007】基于java+servlet+mysql的垃圾分类网站的设计与实现(附源码 配置 文档)

网垃圾分类网站的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 随着全球环境保护意识的提升&#xff0c;垃圾分类已成为一项紧迫且重要的任务。为了有效推动垃圾分类的实施&#xff0c;提升公众的环保意识和参与度&#xff0c;垃圾分类已…

【Python爬虫五十个小案例】爬取豆瓣电影Top250

博客主页&#xff1a;小馒头学python 本文专栏: Python爬虫五十个小案例 专栏简介&#xff1a;分享五十个Python爬虫小案例 &#x1fab2;前言 在这篇博客中&#xff0c;我们将学习如何使用Python爬取豆瓣电影Top250的数据。我们将使用requests库来发送HTTP请求&#xff0c;…

C++ 优先算法 —— 长度最小的子数组(滑动窗口)

目录 题目&#xff1a;长度最小的子数组 1. 题目解析 2. 算法原理 Ⅰ. 暴力枚举 Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 滑动窗口正确性 3. 代码实现 Ⅰ. 暴力枚举(会超时&#xff09; Ⅱ. 滑动窗口&#xff08;同向双指针&#xff09; 题目&#xff1a;长…

C++设计模式——Singleton单例模式

一、单例模式的定义 单例模式&#xff0c;英文全称Singleton Pattern&#xff0c;是一种创建型设计模式&#xff0c;它保证一个类在程序中仅有一个实例&#xff0c;并对外提供一个访问的该类实例的全局接口。 单例模式通常用于需要控制对象资源的开发场景&#xff0c;一个类…

【Linux系统】—— 基本指令(三)

【Linux系统】—— 基本指令&#xff08;三&#xff09; 1 一切皆文件2 重定向操作2.1 初始重定向2.2 重定向的妙用2.3 追加重定向2.4 输入重定向2.5 一切皆文件与重定向结合 3 Linux 中的文件类型4 日志5 「more」命令6 「less」命令7 「head」与「tail」7.1 查看文件开头和结…

探索 Python 任务自动化的新境界:Invoke 库揭秘

文章目录 探索 Python 任务自动化的新境界&#xff1a;Invoke 库揭秘背景&#xff1a;为何选择 Invoke&#xff1f;什么是 Invoke&#xff1f;如何安装 Invoke&#xff1f;5个简单的库函数使用方法1. 定义任务2. 带参数的任务3. 运行 Shell 命令4. 任务参数化5. 列出任务 场景应…

【C++】list模拟实现(详解)

本篇来详细说一下list的模拟实现&#xff0c;list的大体框架实现会比较简单&#xff0c;难的是list的iterator的实现。我们模拟实现的是带哨兵位头结点的list。 1.准备工作 为了不和C库里面的list冲突&#xff0c;我们在实现的时候用命名空间隔开。 //list.h #pragma once #…

shell脚本(6)

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell(6)if条件判断与for循环结构_哔哩哔哩_bilibili 本文主要讲解shell脚本中的if条件判断和for循环结构。 一、if语句 Shell 脚本中的 if 语句…

JavaScript基础 document.write()方法

JavaScript基础 document.write方法 1.简单认识document.write()2.document.write() 的使用 1.简单认识document.write() document.write() 是一种 JavaScript 方法&#xff0c;用于将内容直接写入到 HTML 文档中。它可以用来动态地在页面加载时插入文本、HTML 代码、图片等内…

Linux笔记---进程:进程切换与O(1)调度算法

1. 补充概念 1.1 并行与并发 竞争性&#xff1a;系统进程数目众多&#xff0c;而CPU资源只有少量&#xff0c;甚至只有1个&#xff0c;所以进程之间是具有竞争属性的。为了高效完成任务&#xff0c;更合理竞争相关资源&#xff0c;便具有了优先级。独立性&#xff1a;多进程运…

使用ENSP实现浮动静态路由

一、项目拓扑 二、项目实现 1.路由器AR1配置 进入系统试图 sys将路由器命名为R1 sysname R1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为1.1.1.1/24 ip address 1.1.1.1 24进入g0/0/1接口 int g0/0/1将g0/0/1接口IP地址配置为2.…

GoF设计模式——结构型设计模式分析与应用

文章目录 UML图的结构主要表现为&#xff1a;继承&#xff08;抽象&#xff09;、关联 、组合或聚合 的三种关系。1. 继承&#xff08;抽象&#xff0c;泛化关系&#xff09;2. 关联3. 组合/聚合各种可能的配合&#xff1a;1. 关联后抽象2. 关联的集合3. 组合接口4. 递归聚合接…

【论文复现】深度知识追踪

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 深度知识追踪 1. 论文概述2. 论文方法3. 实验部分3.1 数据集3.2 实验步骤3.3 实验结果 4 关键代码 1. 论文概述 知识追踪的任务是对学生的知…

Linux: 进程地址空间(理解虚拟地址和页表)

目录 1. 虚拟地址 2. 进程地址空间分布 3. 描述进程地址空间 4. 内存管理——页表 5. 父子进程的虚拟地址关系 6. 页表标记位 6.1 读写权限 6.2 命中权限 7.为什么存在进程地址空间 1. 虚拟地址 #include <stdio.h> #include <unistd.h> #include <sy…