【03】C++ 类和对象 2:默认成员函数

文章目录

  • 🌈 前言
  • 🌈 Ⅰ 构造函数
    • 1. 构造函数概念
    • 2. 构造函数特性
    • 3. 初始化列表
  • 🌈 Ⅱ 析构函数
    • 1. 析构函数概念
    • 2. 析构函数特性
  • 🌈 Ⅲ 拷贝构造
    • 1. 拷贝构造概念
    • 2. 拷贝构造特性
    • 3. 深度拷贝构造
  • 🌈 Ⅳ 赋值重载
    • 1. 运算符重载
    • 2. 赋值运算符重载

🌈 前言

1. 默认成员函数介绍

  • 一个什么成员都没有的类简称为空类,编译器会自动为空类生成几个默认成员函数。
  • 默认成员函数:用户不写出来的话,编译器就会生成的成员函数称为默认成员函数。
  • 编译器自动生成的默认成员函数一般都比较挫,因此在大多数情况下就需要我们自己去编写这些个默认成员函数的执行逻辑。

2. 默认成员函数分类

函数功能
构造函数主要完成对成员变量的初始化工作
析构函数主要完成对成员变量的清理工作
拷贝构造使用同类对象初始化新创建的对象
赋值重载把一个对象赋值给另一个对象

🌈 Ⅰ 构造函数

1. 构造函数概念

  • 现定义一个日期 (date) 类
class date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{date d1, d2;d1.Init(2024, 2, 6);	// 调用公有成员函数 Init 为对象 d1 内的成员变量初始化d2.Init(2024, 2, 7);	// 调用公有成员函数 Init 为对象 d2 内的成员变量初始化return 0;
}
  • 对于 date 类,可以使用 Init 公有成员函数来给对象设置日期,但如果每次创建对象时都需要调用该函数来进行成员变量的初始化,需要写两行且很容易忘记,此时构造函数就诞生了。
  • 构造函数是一个特殊的成员函数,该成员函数的名字与类名一致,实例化对象时由编译器自动调用。用来保证每个对象内的成员变量都有一个适当的初始值,且在对象整个生命周期内只调用一次

2. 构造函数特性

  • 构造函数的主要任务是初始化对象

1. 构造函数特性

  1. 函数名和类型相同。
  2. 没有任何返回值。
  3. 实例化对象时编译器自动调用对应的构造函数。
  4. 构造函数也支持重载。
  5. 构造函数也支持缺省参数。

2. 构造函数示例

class date
{
public:// 构造函数:函数名和类名相同,没有返回值,支持缺省参数date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{date d1;				// 不指定初始值时就用缺省参数初始化对象date d2(2024, 2, 7);	// 在实例化对象的同时顺带就能初始化对象return 0;
}

在这里插入图片描述

  • d1 使用缺省参数完成了对象初始化,d2 使用给的值完成了对象初始化。都自动调用了构造函数。

3. 初始化列表

1. 为何使用初始化列表

  • 在构造函数的函数体内对成员变量初始化称为初始化赋值,并不是正儿八经的初始化,是赋值就存在多次赋值的问题。
  • 初始化赋值的问题在构造函数的函数体内没办法解决。因此在构造函数时可以使用一种叫做初始化列表的方式进行初始化。用以确保每个成员变量都只被初始化一次。
class date
{
public:date(int year, int month, int day){_year = year;_month = month;_day = day;_year = 2023;	// 成员变量 _year 被初始化了 2 次这咋个整}
private:int _year;int _month;int _day;
};

2. 初始化列表语法格式

类名(形参列表):成员变量1(成员变量 1 的初始值),成员变量2(成员变量 2 的初始值),成员变量n(成员变量 n 的初始值)
{}

3. 初始化列表示例

class date
{
public:date(int year = 1, int month = 1, int day = 1):_arr((int*)malloc(4 * sizeof(int))),_year(year),_month(month),_day(day){cout << "这是一个构造函数" << endl;}
private:int* _arr;int _year;int _month;int _day;
};

在这里插入图片描述

4. 初始化列表的特性

  1. 每个成员变量在初始化列表中只能出现一次 (只能初始化一次)。
  2. 以下成员变量必须放在初始化列表中进行初始化 (在函数体内对这些成员变量初始化会报错)。
    • 引用成员变量
    • const 成员变量
    • 自定义类型成员 (且该类没有默认构造函数时)
  3. 尽量使用初始化列表进行初始化,因为编译器会优先使用初始化列表。
  4. 成员变量的声明顺序就是成员变量在初始化列表中初始化的顺序。

在这里插入图片描述

🌈 Ⅱ 析构函数

1. 析构函数概念

1. 概念

  • 构造函数将对象内的成员变量初始化,那么析构函数就是将其销毁。
  • 析构函数不是完成对对象本身的销毁,对象是在出了对象所在的作用域或者程序结束时自动销毁。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作

2. 格式

~类名()
{	// 函数体
}

2. 析构函数特性

1. 析构函数特性

  1. 析构函数的函数名由 ~ 和 类名 两部分构成。
  2. 析构函数没有任何参数,也没有返回值。
  3. 一个类中只能由一个析构函数。
  4. 析构函数不能实现函数重载。
  5. 对象的声明周期结束时,编译器会自动调用析构函数。
  6. 如果类初始化时没有申请资源 (开辟空间),析构函数可以不写,反之一定要写。

2. 析构函数示例

  • 现有一个为了实现栈而定义的类。
class stack					// 定义一个用于实现栈的类
{
public:stack(int capacity = 4)	// 构造函数:_array((int*)malloc(4 * sizeof(int))), _top(-1),_capacity(capacity){cout << "stack(int capacity = 4)" << endl;}~stack()				// 析构函数:对象的生命周期结束时自动调用析构函数{free(_array);		// 如果有动态开辟的空间,就不用怕最后会忘记释放了_top = 0;_capacity = 0;cout << "~stack()" << endl;}
private:int* _array;int _top;int _capacity;
};
  • 使用上述 stack 类定义出对象的话就肯定要动态开辟空间,如果没有析构函数自动将开辟的空间释放掉,而自己又忘了将开辟的空间手动释放,内存泄漏这不就来了。

在这里插入图片描述

🌈 Ⅲ 拷贝构造

1. 拷贝构造概念

1. 拷贝构造概念

  • 在实例化对象时,可以不给初始值让构造函数使用缺省参数,也可以给初始值让构造函数对对象进行初始化。拷贝构造就是用一个现有的同类对象去初始化另一个对象

  • 拷贝构造函数只有一个形参 (只显示一个形参,this 指针不显示),该形参是对本类类型对象的引用 (一般常用 const 修饰),在用已存在的同类对象创建新对象时自动调用

2. 拷贝构造语法格式

类名(const 类名& 形参名)	// 实际上还是有两个形参,第一个形参为隐藏的 this 指针
{// 拷贝构造的函数体
}

3. 拷贝构造函数示例

class date
{
public:// 构造函数date(int year = 1, int month = 1, int day = 1): _day(day)	,_year(year),_month(month){}// 拷贝构造函数date(const date& d):_year(d._year),_month(d._month),_day(d._day){}
private:int _year;int _month;int _day;
};int main()
{date d1(2024, 2, 8);	// 调用构造函数对 d1 进行初始化date d2(d1);			// 调用拷贝构造使用 d1 对 d2 进行初始化return 0;
}

在这里插入图片描述

2. 拷贝构造特性

  1. 拷贝构造函数是构造函数的一个函数重载形式,本质还是构造函数。
  2. 拷贝构造函数的显示参数只有一个必须是对实参对象的引用
  3. 如果自己不写拷贝构造函数,编译器会自动生成,默认的拷贝构造函数执行的是浅拷贝。
  4. 拷贝构造函数最常用的调用场景:
    • 使用现有对象初始化创建新对象。
    • 函数参数类型为类类型对象。
    • 函数返回值为类类型对象。

3. 深度拷贝构造

1. 默认的拷贝构造函数执行的是浅拷贝

  • 浅拷贝:如果某个对象内的一个成员变量是一个指向一块连续空间的指针,那么浅拷贝就是将该地址拷贝给另一个对象的。两个对象各自的成员变量指向同一块空间。
  • 深拷贝:为新对象重新开辟一块同样大小的空间,并且将已有对象内的值拷贝过去。

在这里插入图片描述
在这里插入图片描述

2. 深度拷贝构造示例

class stack
{
public:stack(int capacity = 4)	// 构造函数{_array = (int*)malloc(sizeof(int) * capacity);assert(_array);_top = -1;_capacity = capacity;}stack(const stack& s)	// 拷贝构造,this 是 st2,s 是 st1{int* tmp = (int*)malloc(s._capacity * sizeof(int));assert(tmp);// 将 st1 的 array 中的有效数据拷贝给 st2 的 arraymemcpy(tmp, s._array, sizeof(int) * (s._top + 1));_array = tmp;_top = s._top;_capacity = s._capacity;}
private:int* _array;int _top;int _capacity;
};

在这里插入图片描述

🌈 Ⅳ 赋值重载

1. 运算符重载

1. 运算符重载概述

  • 有些时候函数名无法一眼看出该函数是为了实现什么功能 (如 func1、func2 这种函数名完全看不出该函数是要用来干什么)。
  • 运算符重载是具有特殊函数名的函数,是为了增强代码的可读性而被引入。

2. 运算符重载格式

函数返回值类型 operator操作符(形参列表)
{函数体
}

3. 赋值运算符示例

  • 现在要判断两个日期类的对象是否相等,内置操作符无法直接进行判断。因此将 == 进行重载以表示这是一个判断对象是否相等的成员函数。
class date
{
public:date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 将 == 重载成判断两个类类型对象是否相等的运算符bool operator== (const date& d)	// 此处的 this 表示 d1,d 表示 d2{return _year == d._year && _month == d._month && _day == d._day;}
private:int _year;int _month;int _day;
};

在这里插入图片描述

4. 运算符重载本质

  • 上述的 d1 == d2 实际上在编译器看来是 d1.operator==(d2),本质上还是调用对应的成员函数,然后将 d1 的地址传给 this 指针,形参 d 引用了 d2。

5. 运算符重载特性

  1. 不能通过连接其他符号来创建新的操作符,如 operator 和 @ 组成的 operator@ 不是一个新的操作符。
  2. 重载操作符必须有一个自定义类型的参数。
  3. 不能改变用于内置类型的运算符的含义,如 不能将 加法 的含义重载成 减法。
  4. 除了以下 5 种运算符,其余运算符都能被重载:
    • 点星 ( .* ),域作用限定符 ( :: ),计算大小 ( sizeof ),三目运算符 ( ?: ),点 ( . )

2. 赋值运算符重载

1. 赋值重载功能

  • 实现类类型对象之间的赋值,现在有两个已经被实例化好的对象 A、B,赋值重载就是将 对象 A 的值赋值给 对象 B。
  • 和拷贝构造不一样,拷贝构造是用一个定义好的对象去初始化一个未被定义的对象。

2. 赋值重载格式

  • 形参类型:const 类名&,传引用可以提高传参效率。
  • 返回值类型:类名&,设置返回值是为了支持连续赋值 (A = B = C 这样)。
  • 检测是否自己给自己赋值
  • 返回 *this,为了实现连续赋值。

3. 赋值重载示例

class date
{
public:date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}date& operator=(const date& d)	// this 指针指向 d1,d 表示 d2{if (this != &d)				// 避免自己给自己赋值{_year = d._year;_month = d._month;_day = d._day;}return *this;				// 返回对 d1 的引用}
private:int _year;int _month;int _day;
};

在这里插入图片描述

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

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

相关文章

【LeetCode每日一题】525连续数组 303区域和检索(前缀和的基本概念和3个简单案例)

前缀和 // 构造prefix let prefix [0] arr.forEach(num > {prefix.push(prefix.at(-1) num); })如果想要计算某个区间 i 到 j 这个子数组的和时&#xff0c;可以根据 prefix[j1] - prefix[i] 获得。 例题1&#xff1a;303.区域和检索 - 数组不可变 给定一个整数数组 num…

3分钟部署完成Docker Registry及可视化管理工具Docker-UI

安装docker-registry 由于镜像文件会非常占用空间&#xff0c;因此需要选择一个磁盘充裕的位置来存放镜像数据。 这里设置为&#xff1a;-v /data/registry:/var/lib/registry&#xff0c;其中/data/registry是宿主机存放数据的位置。 docker run -d -p 5000:5000 --restart…

龙芯开启ssh服务——使用Putty连接

本文采用龙芯3A6000处理器&#xff0c;Loongnix操作系统。 为了能使用其他电脑远程操控龙芯电脑&#xff0c;需要打开loongnix的ssh服务&#xff0c;并在其他电脑里使用putty连接loongnix。 1 修改ssh配置文件 命令行输入&#xff1a; sudo vim /etc/ssh/sshd_config按下i插…

JetpackCompose之状态管理

JetPack Compose系列&#xff08;13&#xff09;—状态管理 State 即&#xff0c;状态。官方的解释是&#xff1a; State in an application is any value that can change over time. And ****event can notify a part of a program that something has happened. 可以这样…

Linux版Black Basta勒索病毒针对VMware ESXi服务器

前言 Black Basta勒索病毒是一款2022年新型的勒索病毒&#xff0c;最早于2022年4月被首次曝光&#xff0c;主要针对Windows系统进行攻击&#xff0c;虽然这款新型的勒索病毒黑客组织仅仅才出来短短两个多月的时间&#xff0c;就已经在其暗网平台上已经公布了几十个受害者之多&…

消息中间件:Puslar、Kafka、RabbigMQ、ActiveMQ

消息队列 消息队列&#xff1a;它主要用来暂存生产者生产的消息&#xff0c;供后续其他消费者来消费。 它的功能主要有两个&#xff1a; 暂存&#xff08;存储&#xff09;队列&#xff08;有序&#xff1a;先进先出 从目前互联网应用中使用消息队列的场景来看&#xff0c;…

小项目:蓝牙模块点亮RGB三色灯

在之前的教程中&#xff0c;我们学习了蓝牙模块的原理&#xff0c;并动手写了驱动&#xff0c;实现了串口的接收和发送。本次我们就来教大家如何使用蓝牙串口控制灯。这是一个简单的示例&#xff0c;展示了如何将蓝牙通信与硬件控制相结合&#xff0c;实现远程控制的功能。你也…

机器学习系列——(十九)层次聚类

引言 在机器学习和数据挖掘领域&#xff0c;聚类算法是一种重要的无监督学习方法&#xff0c;它试图将数据集中的样本分组&#xff0c;使得同一组内的样本相似度高&#xff0c;不同组间的样本相似度低。层次聚类&#xff08;Hierarchical Clustering&#xff09;是聚类算法中的…

战略规划的重要性及撰写步骤

当新的季度或财年到来的时候&#xff0c;团队需要确定首要开始的工作内容&#xff0c;但团队成员对于应优先处理的事务很多时候都持有不同观点&#xff0c;每个人都认为自己的任务应该被优先考虑&#xff0c;这种决策过程耗费了大量时间&#xff0c;以至于团队经常推迟计划的开…

C#,聚会数(相遇数,Rencontres Number)的算法与源代码

1 相遇数 相遇数&#xff08;Rencontres Number&#xff0c;partial derangement numbers&#xff09;是指部分扰动的数量&#xff0c;或与独立对象的r相遇的置换数&#xff08;即具有固定点的独立对象的置换数&#xff09;。 看不通。懂的朋友给解释一下哈。 2 源程序 using…

在 VMware 虚拟机上安装 CentOS系统 完整(全图文)教程

一、前期准备&#xff1a; 1.安装VMware 虚拟机软件&#xff08;不在讲解&#xff0c;可自行去下载安装&#xff09;。官网&#xff1a;https://customerconnect.vmware.com/cn/downloads/details?downloadGroupWKST-PLAYER-1750&productId1377&rPId111471 2.下载iso…

机器学习系列——(二十)密度聚类

引言 在机器学习的无监督学习领域&#xff0c;聚类算法是一种关键的技术&#xff0c;用于发现数据集中的内在结构和模式。与传统的基于距离的聚类方法&#xff08;如K-Means&#xff09;不同&#xff0c;密度聚类关注于数据分布的密度&#xff0c;旨在识别被低密度区域分隔的高…