当前位置: 首页 > news >正文

【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

在这里插入图片描述

C++入门

  • 六个默认成员函数
  • 1 构造函数
    • 语法
    • 特性
  • 2 析构函数
    • 语法
    • 特性
  • 3 拷贝构造函数
    • 特性
  • 4 赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 特例:前置++ 与 后置++
      • 前置++:返回+1之后的结果
      • 后置++:
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

六个默认成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗? 并不是
任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数
我们实现了,编译器就不会生成了
在这里插入图片描述

1 构造函数

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证
每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

语法

  1. 函数名与类名相同。
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载(最好实现一个全缺省的构造函数)
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}void show() {cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);//默认构造Date yesterday(2024, 2, 17);//默认构造today.show();yesterday.show();return 0;
}

来看效果在这里插入图片描述

特性

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

  2. 关于编译器生成的默认成员函数,有个疑惑:不实现构造函数的情况下,编译器会生成 默认的构造函数。但是看起来默认构造函数又没什么用?Date对象调用了编译器生成的默认构造函数,但是Date对象_year / _month / _day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员 _t 调用的它的默认成员函数。

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

上面程序会对 _t 进行默认构造,由于我们编写了构造函数,_t 中 的内容成功初始化,但是_year / _month / _day缺依然是随机值。

  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数

2 析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

语法

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
    下面的栈可以帮助我们理解析构函数的作用
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 析构函数~Stack(){	//如果 不为空if (_array){   // 释放指针free(_array);//初始化_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);//生命周期结束自动析构清理
}

特性

关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

调用自定义类型 time 的析构函数
在这里插入图片描述
注意 :
析构函数的调用顺序,先创建先销毁,先销毁局部变量,在销毁全局变量。
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类

3 拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用

特性

  1. 拷贝构造是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用直接的传值编译器会直接报错,因为会引发无穷递归调用。
    原因:传值拷贝时
    第一步:开辟一个临时空间;
    第二步:由于临时空间是需要构造的,重新调用拷贝构造函数(无穷递归形成…)

在这里插入图片描述

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
  2. 浅拷贝不能实现复杂的类拷贝,涉及指针等内容会拷贝失败。
  3. 拷贝构造函数典型调用场景:
    使用已存在对象创建新对象
    函数参数类型为类类型对象
    函数返回值类型为类类型对象

4 赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator"操作符" (参数列表)

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  4. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

来看样例:

class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date yesterday(2024, 2, 17);today.show();yesterday.show();cout << "operator==()\n" << (today == yesterday) << endl;return 0;
}

在这里插入图片描述不相等返回假。

赋值运算符重载

  1. 赋值运算符重载格式
    参数类型:const T&,传递引用可以提高传参效率
    返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
    检测是否自己给自己赋值
    返回*this :要复合连续赋值的含义
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}//运算符重载bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}//赋值运算符重载Date& operator=(const Date& d){if(this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date day = today;today.show();day.show();return 0;
}

在这里插入图片描述
可以成功赋值。

  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数
    原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数
  2. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了
还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType *_array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2;s2 = s1;return 0;
} 

这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现

特例:前置++ 与 后置++

前置++:返回+1之后的结果


// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
{_day += 1;return *this;
}

后置++:

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
注意:
后置++是 先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1,


Date operator++(int)
{Date temp(*this);_day += 1;// temp是临时对象,因此只能以值的方式返回,不能返回引用return temp;
}

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

相关文章:

【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

C入门 六个默认成员函数1 构造函数语法特性 2 析构函数语法特性 3 拷贝构造函数特性 4 赋值运算符重载运算符重载赋值运算符重载特例&#xff1a;前置 与 后置前置&#xff1a;返回1之后的结果后置&#xff1a; Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读&…...

沁恒CH32V30X学习笔记04--外部中断

外部中断 CH32V2x 和 CH32V3x 系列内置可编程快速中断控制器(PFIC– Programmable Fast Interrupt Controller),最多支持 255 个中断向量。当前系统管理了 88 个外设中断通道和 8 个内核中断通道 PFIC 控制器 88个外设中断,每个中断请求都有独立的触发和屏蔽控制位,有专…...

基础IO[三]

close关闭之后文件内部没有数据&#xff0c; stdout和stderr 他们一起重定向&#xff0c;只会重定向号文件描述符&#xff0c;因为一号和二号描述符虽然都是sydout&#xff0c;但是并不一样&#xff0c;而是相当于一个显示器被打开了2次。 分别重定向到2个文件的写法和直接写道…...

Leetcode 392 判断子序列

题意理解&#xff1a; 给定字符串 s 和 t &#xff0c;判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些&#xff08;也可以不删除&#xff09;字符而不改变剩余字符相对位置形成的新字符串。&#xff08;例如&#xff0c;"ace"是"abcde&quo…...

基于微信小程序的校园跑腿系统的研究与实现,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

VTK Python PyQt 监听键盘 控制 Actor 移动 变色

KeyPressInteractorStyle 在vtk 中有时我们需要监听 键盘或鼠标做一些事&#xff1b; 1. 创建 Actor&#xff1b; Sphere vtk.vtkSphereSource() Sphere.SetRadius(10)mapper vtk.vtkPolyDataMapper() mapper.SetInputConnection(Sphere.GetOutputPort()) actor vtk.vtkAc…...

力扣 第 124 场双周赛 解题报告 | 珂学家 | 非常规区间合并

前言 整体评价 T4的dp解法没想到&#xff0c;走了一条"不归路", 这个区间合并解很特殊&#xff0c;它是带状态的&#xff0c;而且最终的正解也是基于WA的case&#xff0c;慢慢理清的。 真心不容易&#xff0c;太难了。 T1. 相同分数的最大操作数目 I 思路: 模拟 c…...

2024年华为OD机试真题-生成哈夫曼树-Java-OD统一考试(C卷)

题目描述: 给定长度为n的无序的数字数组,每个数字代表二叉树的叶子节点的权值,数字数组的值均大于等于1。请完成一个函数,根据输入的数字数组,生成哈夫曼树,并将哈夫曼树按照中序遍历输出。 为了保证输出的二叉树中序遍历结果统一,增加以下限制:二叉树节点中,左节点权…...

【实战】二、Jest难点进阶(二) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(六)

文章目录 一、Jest 前端自动化测试框架基础入门二、Jest难点进阶2.mock 深入学习 学习内容来源&#xff1a;Jest入门到TDD/BDD双实战_前端要学的测试课 相对原教程&#xff0c;我在学习开始时&#xff08;2023.08&#xff09;采用的是当前最新版本&#xff1a; 项版本babel/co…...

(一)【Jmeter】JDK及Jmeter的安装部署及简单配置

JDK的安装和环境变量配置 对于Linux、Mac和Windows系统,JDK的安装和环境变量配置方法略有不同。以下是针对这三种系统的详细步骤: 对于Linux系统: 下载适合Linux系统的JDK安装包,可以选择32位或64位的版本。 将JDK的安装包放置在服务器下,创建一个新的文件夹来存储JDK,…...

HAL/LL/STD STM32 U8g2库 +I2C SSD1306/sh1106 WouoUI磁贴案例

HAL/LL/STD STM32 U8g2库 I2C SSD1306/sh1106 WouoUI磁贴案例 &#x1f4cd;基于STM32F103C8T6 LL库驱动版本&#xff1a;https://gitee.com/chcsx/platform-test/tree/master/MDK-ARM&#x1f3ac;视频演示&#xff1a; WouoUI移植磁贴案例&#xff0c;新增确认弹窗 &#x1f…...

手机如何改自己的ip地址

在现如今的数码时代&#xff0c;手机已经成为人们生活中不可或缺的一部分。然而&#xff0c;有时候我们可能需要改变手机的IP地址来实现一些特定的需求。本文将向大家介绍如何改变手机的IP地址&#xff0c;帮助大家更好地应对各种网络问题。 更改手机IP地址的原因&#xff1a;…...

ajax函数库axios基本使用

ajax函数库Axios基本使用 简介&#xff1a;Axios 对原生的Ajax进行了封装&#xff0c;简化书写&#xff0c;快速开发。 官网&#xff1a;https://www.axios-http.cn/ Axios使用步骤 引入Axios的js文件(参考官网)使用Axios发送请求,获取相应结果 <script src"https:…...

【nginx实践连载-4】彻底卸载Nginx(Ubuntu)

步骤1&#xff1a;停止Nginx服务 打开终端&#xff08;Terminal&#xff09;。停止Nginx服务&#xff1a;sudo systemctl stop nginx步骤2&#xff1a;卸载Nginx软件包 运行以下命令卸载Nginx软件包&#xff1a;sudo apt purge nginx nginx-common nginx-core步骤3&#xff1…...

究极小白如何自己搭建一个自动发卡网站-独角数卡

首页 | 十画IOSID​shihuaid.cn/​编辑 如果你也是跟我一样,什么都不懂,也想要搭建一个自己的自动发卡网站,可以参考一下我的步骤,不难,主要就是细心,一步步来一定成功!! 独角数卡: 举个例子:独角数卡就是一个店面,而且里面帮你装修好了,而你要做的就是把开店之…...

Java_方法(重载方法签名等详解)

在之前我们学习C语言时&#xff0c;当我们想要重复使用某段代码的功能时&#xff0c;我们会将这段代码定义为一个函数&#xff0c;而在java中我们把这段重复使用的代码叫做方法。 方法的定义 类体的内容分为变量的声明和方法的定义&#xff0c;方法的定义包括两部分&#xff1…...

VQ35 评论替换和去除(char_length()和replace函数的使用)

代码 select id ,replace(comment,&#xff0c;,) as comment from comment_detail where char_length(comment)>3知识点 要注意替换的是中文逗号 由于题目说的是汉字长度大于3&#xff0c;所以这里就要使用char_length()而不是length() char_length()&#xff1a;单位为字…...

【MySQL】学习多表查询和笛卡尔积

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-N8PeTKG6uLu4bJuM {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...

RabbitMQ实现延迟消息的方式-死信队列、延迟队列和惰性队列

当一条消息因为一些原因无法被成功消费&#xff0c;那么这这条消息就叫做死信&#xff0c;如果包含死信的队列配置了dead-letter-exchange属性指定了一个交换机&#xff0c;队列中的死信都会投递到这个交换机内&#xff0c;这个交换机就叫死信交换机&#xff0c;死信交换机再绑…...

【运维测试】测试理论+工具总结笔记第1篇:测试理论的主要内容(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论测试理论测试工具相关知识。Python测试理论的主要内容&#xff0c;掌握软件测试的基本流程&#xff0c;知道软件测试的V和W模型的优缺点&#xff0c;掌握测试用例设计的要素&#xff0c;掌握等价类划分法、边界值法、因…...

【C语言】实现队列

目录 &#xff08;一&#xff09;队列 &#xff08;二&#xff09;头文件 &#xff08;三&#xff09; 功能实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09; 销毁队列 &#xff08;3&#xff09; 入队 &#xff08;4&#xff09;出队 &#xff08;5&a…...

【友塔笔试面试复盘】八边形取反问题

问题&#xff1a;一个八边形每条边都是0&#xff0c;现在有取反操作&#xff0c;选择一条边取反会同时把当前边和2个邻边取反&#xff08;如果是0变为1&#xff0c;如果是1变为0&#xff09; 现在问你怎么取反能使得八条边都变为1. 当时陷入了暴力递归漩涡&#xff0c;给出一个…...

GB 18585-2023 壁纸中有害物质限量

壁纸/墙布因其色彩多样&#xff0c;图案丰富&#xff0c;施工方便&#xff0c;价格便宜等多种优势&#xff0c;广泛应用于室内装修材料&#xff0c;在国内&#xff0c;日本&#xff0c;欧美等地区非常普及。 GB 18585-2023壁纸中有害物质限量测试项目&#xff1a; 测试项目 测…...

全面的ASP.NET Core Blazor简介和快速入门

前言 因为咱们的MongoDB入门到实战教程Web端准备使用Blazor来作为前端展示UI&#xff0c;本篇文章主要是介绍Blazor是一个怎样的Web UI框架&#xff0c;其优势和特点在哪&#xff1f;并带你快速入门上手ASP.NET Core Blazor(当然这个前提是你要有一定的C#编程基础的情况&#x…...

HGAME 2024 WEEK2 Crypto WP

前言 我很菜&#xff0c;有没做出来的题目&#xff0c;带*号题为复现。 midRSA 题目&#xff1a; from Crypto.Util.number import * from secret import flagdef padding(flag):return flagb\xff*(64-len(flag))flagpadding(flag) mbytes_to_long(flag) pgetPrime(512) qg…...

Postman轻松签名,让SHA256withRSA保驾护航!

前言 在接口测试中&#xff0c;我们经常需要对请求进行签名&#xff0c;以保证数据的安全性。而SHA256withRSA是一种较为常见的签名算法&#xff0c;它可以使用私钥对数据进行签名&#xff0c;使用公钥进行验签。 但是&#xff0c;实现该算法签名可能会涉及到一些繁琐的操作&…...

C#面:简述装箱和拆箱

在C#中&#xff0c;装箱&#xff08;boxing&#xff09;和拆箱&#xff08;unboxing&#xff09;是用于在值类型和引用类型之间进行转换的过程。 装箱&#xff1a;&#xff08;Boxing&#xff09; 是将值类型转换为引用类型的过程。 将一个值类型赋值给一个对象类型时&#x…...

【Kubernetes in Action笔记】1.快速开始

在Kubernetes上运行一个程序 基础运行环境 当前的运行环境为使用虚拟机构建的单master集群。 [rootk8s-master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane 109d v1.27.1 k8s-node1 Ready …...

踩坑实录(Fourth Day)

今天开工了&#xff0c;其实还沉浸在过年放假的喜悦中……今天在自己写 Vue3 的项目&#xff0c;虽说是跟着 B 站在敲&#xff0c;但是依旧是踩了一些个坑&#xff0c;就离谱……照着敲都能踩到坑&#xff0c;我也是醉了…… 此为第四篇&#xff08;2024 年 02 月 18 日&#x…...

【python】网络爬虫与信息提取--requests库

导学 当一个软件想获得数据&#xff0c;那么我们只有把网站当成api就可以 requests库:自动爬取HTML页面&#xff0c;自动网络请求提交 robots协议&#xff1a;网络爬虫排除标准&#xff08;网络爬虫的规则&#xff09; beautiful soup库&#xff1a;解析HTML页面 工具&…...