C++ 类和对象篇(三) 空类和6个默认成员函数

news2024/9/25 1:23:22

目录

一、空类

1. 是什么?

2. 空类中的成员

3. 空类的大小

二、6个默认成员函数

三、 构造函数

1. 构造函数是什么?

2. 为什么C++要引入构造函数?

四、析构函数

1. 析构函数是什么?

2. 为什么要有析构函数?

五、拷贝构造函数

1. 拷贝构造函数是什么?

2. 为什么要有拷贝构造函数?

六、赋值运算符重载函数

1. 运算符重载是什么?

2. 为什么要运算符重载?

3. 默认赋值运算符重载函数

七、取地址运算符重载

1. 为什么需要重载取地址运算符?

2. 默认取地址运算符重载函数

3. 默认const取地址运算符重载函数

八、默认成员函数什么情况需要显示去写?


一、空类

1. 是什么?

如果一个类中没有显示定义任何成员,简称为空类。

class A {};//一个空类

2. 空类中的成员

空类中真的什么都没有吗?

并不是,任何类都有6个不在类中实现,编译器会自动生成的默认成员函数。

3. 空类的大小

        注意,没有成员变量的类(包括空类)的大小为1字节,不存储数据,目的是为了占位,标识对象存在,区分不同的对象。所以,空类同样可以被实例化,并且每个实例在内存中都有独一无二的地址。


二、6个默认成员函数

默认成员函数:用户在类中没有显式实现,编译器会自动生成的成员函数称为默认成员函数。

1)构造函数:在创建对象时初始化对象中的成员变量。

2)析构函数:完成对象的销毁。

3)拷贝构造函数:有了该函数能用同类对象初始化创建对象。

4)赋值重载函数:有了该函数能把一个对象赋值给另一个对象。

5)普通对象取地址重载函数:主要是对普通对象取地址,这个很少会自己实现。

6)const对象取地址重载函数:主要是对const对象取地址,这个很少会自己实现。

不能以普通函数的定义和调用规则去理解以上6个函数。


三、 构造函数

1. 构造函数是什么?

        构造函数是一个特殊的成员函数用来初始化成员变量,函数名和类名相同,使用实例化对象时由编译器自动调用,并且在对象整个生命周期内只调用一次。

2. 为什么C++要引入构造函数?

        怎么对类中的成员变量进行初始化?写一个成员函数专门用来初始化成员变量?但如果忘记调用了怎么办?为解决类初始化和忘记初始化类的问题,能不能在创建对象时就自动完成初始化的动作呢?

举个小例子: 
有以下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;
};

如果要使用该Date类创建对象,必须通过Init公有方法给对象设置日期,否则成员变量都是随机值,
但每次创建对象时都调用该方法,这未免有点麻烦,那能否在对象创建的同时,就将信息设置进去呢?

        为解决以上问题,C++中引入了构造函数:构造函数用于对象的初始化,在实例化对象时由编译器自动调用,保证了对象创建出来一定完成了初始化。虽然构造函数叫做构造,但构造函数并不用来开空间创建对象,而是用来初始化对象的。(也许构造函数更适合被称为初始化函数?) 

想要更深入的了解析构函数,可以看看博主的文章: C++ 类和对象篇(四) 构造函数


四、析构函数

1. 析构函数是什么?

        析构函数是一个特殊的成员函数,用来释放对象使用的资源(如关闭文件、释放内存等)。

2. 为什么要有析构函数?

        如何释放对象申请的系统资源?忘记释放怎么办?能不能在销毁对象时自动释放?

举个小例子:
class Test
{
public:
	//构造函数
	Test()
	{
		_arr = (char*)malloc(1024*1024*1024);//申请1G空间
	}
	//销毁函数:用于释放资源
	void Destory()
	{
		free(_arr);
	}
private:
	char* _arr;
};

int main()
{
	Test* t = new Test;//在堆上创建一个对象
	delete t;//销毁一个对象
	while (1) {}
	return 0;
}

如果要销毁Test对象,必须先使用Destory公有方法来释放资源,否则会造成内存泄漏,
这未免有点麻烦,而且容易忘记,那能否在对象销毁的同时释放资源呢?

将以上程序运行起来,对比前后的内存变化,可以发现销毁对象前如果忘记释放资源,就会造成内存泄漏等问题。

程序运行前: 

程序运行后:


        所以为避免C++使用者在销毁对象时忘记释放对象使用的资源的问题,C++引入了析构函数,在析构函数里写释放资源的代码,在对象销毁时编译器会自动调用析构函数释放对象使用的资源。

        析构函数相对于自己写的销毁函数,其优势在于不需要自己去显示调用。 

想要更深入的了解构造函数,可以看看博主的文章:C++ 类和对象篇(五) 析构函数


五、拷贝构造函数

1. 拷贝构造函数是什么?

        拷贝构造函数是一个特殊的构造函数,也是用来初始化对象的,不过它是用已经存在的对象来初始化同类对象。

2. 为什么要有拷贝构造函数?

        在创建新对象时,可否用已经存在的同类对象来初始化这个新对象呢?能否快速拷贝出一个对象的副本呢?为解决以上问题,C++中引入了拷贝构造函数:拷贝构造函数用于实现对象的复制和初始化。

想要更深入的了解拷贝构造函数,可以看看博主的文章:C++ 类和对象篇(六) 拷贝构造函数


六、赋值运算符重载函数

1. 运算符重载是什么?

        运算符重载是一种在编程中扩展或改变已有运算符功能的技术。简单来说,运算符重载就是对已有的运算符重新进行定义,让运算符能够处理特定类型的对象。

2. 为什么要运算符重载?

如果想要让两个对象比较大小该怎么办?有没有办法直接使用运算符>, <来比较两个对象的大小?

class A
{
public:
	A(int a)
	{
		num = a;
	}
	int max(A b)
	{
		return num > b.num;
	}
	int operator> (A b)
	{
		return num > b.num;
	}
private:
	int num;
};
int main()
{
	A a(10);
	A b(20);
    //如果不使用运算符重载,只能编写函数来比较两个对象的大小
	cout << a.max(b) << endl;
    //使用运算符重载
    cout << (a > b) << endl;
	return 0;
}

运算符重载的目的是为了让自定义类型能够使用运算符。
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,其目的就是让自定义类型可以像内置类型一样可以直接使用运算符进行操作。

3. 默认赋值运算符重载函数

        赋值运算符重载函数的特殊在于:只能在类中定义,用户在类中没有显式实现时,编译器会生成一个默认赋值运算符重载函数,以值的方式逐字节拷贝。注意:默认赋值运算符重载函数里内置类型成员变量是直接赋值的,而自定义类型成员变量会调用对应类的赋值运算符重载函数完成赋值:

想要更深入的了解赋值运算符重载函数,可以看看博主的文章:C++ 类和对象篇(七) 运算符重载


七、取地址运算符重载

1. 为什么需要重载取地址运算符?

        在上面分析了重载运算符的原因:为了让自定义类型能使用运算符。重载取地址运算符的目的也是如此:让自定义类型也能使用取地址运算符(&)。

2. 默认取地址运算符重载函数

        类中有6个默认成员函数,其中就有默认取地址运算符重载函数,所以即使类中没有定义取地址运算符重载函数,对象依然能使用取地址运算符(&):

3. 默认const取地址运算符重载函数

        const取地址运算符重载函数也是默认成员函数,所以即使类中没有定义取地址运算符重载函数,const对象依然能使用取地址运算符(&):

想要更深入的了解取地址运算符重载函数,可以看看博主的文章:C++ 类和对象篇(八) const成员函数和取地址运算符重载


八、默认成员函数什么情况需要显示去写?

1. 构造函数:大部分类都建议显示写一个全缺省的构造函数,除了只有自定义类型成员变量的类。

2. 析构函数:只有在类中申请了系统资源(如:使用malloc在堆上申请空间、申请文件描述符)我们才需要显示写析构函数,在析构函数中释放这些申请的系统资源。

3. 拷贝构造函数: 在堆上申请了空间的类,需要我们显示写拷贝构造函数,默认的拷贝构造函数是浅拷贝,会产生重复析构问题。

4. 赋值运算符重载函数:在堆上申请了空间的类,需要我们显示写赋值运算符重载函数,默认的赋值运算符重载函数是浅拷贝,会产生重复析构问题。

5. 取地址重载函数和const取地址重载函数:绝大多数情况下不需要显示去写,默认生成的完全够用。特殊情况下,比如不想让别人获取对象的地址,就可以自己实现,返回nullptr。

        如果一个类只有自定义类型成员变量,且自定义类型成员变量的构造、拷贝构造、赋值重载、默认析构都写好时,该类不需要显示写任何成员函数.


举个例子:当Stack类的构造、拷贝构造、赋值重载、默认析构都写好时,以下的MyQueue类的默认生成都可以用。


------------------------END-------------------------

才疏学浅,谬误难免,欢迎各位批评指正。

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

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

相关文章

硬件信号协议UART是干啥的?

UART协议是电子传输中一种常见的信号协议&#xff0c;通常只需要三根信号线就可以完成数据的收发&#xff0c;分别是TX&#xff0c;RX&#xff0c;GND。 UART(universal asynchronous receiver transmitter)&#xff0c;是通用异步收发器&#xff0c;因为是异步&#xff0c;所以…

312.戳气球

将戳气球转换到添加气球&#xff0c;记忆搜索slove(i,j)&#xff1a;在开区间(i,j)全部填满气球得到的最多硬币数&#xff0c;两端val[i]、val[j] class Solution { public:vector<vector<int>> ans;vector<int> val;int slove(int left,int right){if(left&…

分布式存储系统如何应对SSD硬盘UNC坏块可靠性问题?

Uncorrectable Bit Errors&#xff08;UNC&#xff09;&#xff0c;也有时候叫做Media Error&#xff08;介质错误&#xff09;是指在闪存设备中出现的无法修复的位错误。Media Error的产生意味着即使硬盘自身已经用尽了所有容错手段&#xff08;如LDPC解码&#xff0c;retry等…

75.颜色分类

原地排序&#xff1a;空间复杂度为1 class Solution { public:void sortColors(vector<int>& nums) {if(0){//法一&#xff1a;单指针两个遍历int nnums.size();int ptr0;for(int i0;i<n;i){if(nums[i]0){swap(nums[i],nums[ptr]);ptr;}}for(int iptr;i<n;i){…

win11安装双系统Ubuntu的坎坷记录

之前一直装的都是在一个硬盘中&#xff0c;这是是两块盘。 我的电脑是惠普暗影精灵8Pro 一 安装前的准备工作 1.1 记得先关闭&#xff0c;Bitlocker 输入wins&#xff0c;搜索框输入&#xff1a;设备加密设置 1.2 BIOS设置 &#xff08;惠普这电脑是开机时按 F10&#xff0…

断点测试怎么做,一文教你用Charles 工具做好接口测试!

在测试工作过程中&#xff0c;我们经常会在程序的某一行或者某一环节设置断点&#xff0c;在程序请求的过程中&#xff0c;修改断点处的参数、请求或者响应&#xff0c;这就是所谓的断点测试。这类断点测试主要用于接口测试。 断点测试可以通过查看接口返回数据可以方便定位是前…

015-衍生版本开发

衍生版本开发 文章目录 衍生版本开发项目介绍衍生版本开发波形分析设置CPU 亲缘性 总结 关键字&#xff1a; Qt、 Qml、 关键字3、 关键字4、 关键字5 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个项目结合了 QML&#xff08;Qt Meta-Object Language&#…

【Linux】基本指令-入门级文件操作(一)

目录 前言 ⭕linux的树状文件结构 ⭕绝对路径和相对路径 ⭕当前路径和上级路径 ⭕隐藏文件 基本指令&#xff08;重点&#xff09; 1 pwd 指令 2 mkdir 指令 3 touch 指令 4 ls 指令 4.1 ls只加选项不加文件/目录名&#xff0c;默认查看当前目录下的文件 4.1.1 ls -a…

360 G800行车记录仪,不使用降压线如何开机,8芯插头的定义。

G800记录仪的插头是这样的&#xff0c;图中标出了线的颜色。其中红色为常电V&#xff0c;黑色为GND负极&#xff0c;黄色为ACC受车是否启动控制。 这个记录仪原装的电源线没有降压功能&#xff0c;所以这里的V是12V。 记录仪内部有电源板&#xff0c;负责将12V降压为5V。 如果…

CSS盒子定位的扩张

定位的扩展 绝对定位&#xff08;固定定位&#xff09;会完全压住盒子 浮动元素不会压住下面标准流的文字&#xff0c;而绝对定位或固定位会压住下面标准流的所有内容 如果一个盒子既有向左又有向右&#xff0c;则执行左&#xff0c;同理执行上 显示隐藏 display: none&…

Tasmota系统之MQTT配置和使用篇

Tasmota系统之MQTT配置和使用篇 &#x1f6a9;相关篇《ESP32/ESP8266在线刷写Sonoff Tasmota固件以及配置简要》&#x1f4cc;《Tasmota系统之外设配置》&#x1f4cd;Tasmota官方对MQTT功能使用介绍&#xff1a;https://tasmota.github.io/docs/MQTT/ &#x1f6e0;MQTT本地化…

消息队列 Kafka

Kafka Kafka 是一个分布式的基于发布/订阅模式的消息队列&#xff08;MQ&#xff0c;Message Queue&#xff09;&#xff0c;主要应用于大数据实时处理领域 为什么使用消息队列MQ 在高并发环境下&#xff0c;同步请求来不及处理会发生堵塞&#xff0c;从而触发too many conne…

团队协作中如何处理ConflictingBeanDefinitionException异常

&#x1f47c; 前言 当使用Spring框架进行Java应用程序开发时&#xff0c;可能会遇到ConflictingBeanDefinitionException异常。 如&#xff1a; org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘xxxBean’ …

Spring5应用之AOP注解编程

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Spring5应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言开发…

2.1 Qemu系统模拟:简介

目录 1 后端/加速器2 特性简介3 运行 1 后端/加速器 系统模拟主要用于在host设备上运行guest OSQEMU支持多种hypervisors,同时也支持JIT模拟方案&#xff08;TCG&#xff09; 例如从上表我们可以看出&#xff0c;运行在x86硬件上的Linux系统支持KVM,Xen,TCG 2 特性简介 提供…

【kubernetes】带你了解k8s中PV和PVC的由来

文章目录 1 为什么需要卷(Volume)2 卷的挂载2.1 k8s集群中可以直接使用2.2 需要额外的存储组件2.3 公有云 2 PV(Persistent Volume)3 SC(Storage Class) 和 PVC(Persistent Volume Claim)4 总结 1 为什么需要卷(Volume) Pod是由一个或者多个容器组成的&#xff0c;在启动Pod中…

C++11(下)

目录 一、类的新功能1.1 默认成员函数1.2 类成员变量初始化1.3 强制生成默认函数的关键字default1.4 禁止生成默认函数的关键字delete1.5 继承和多态中的final与override关键字 二、可变参数模板三、lambda表达式3.1 C98中的一个例子3.2 lambda表达式3.3 lambda表达式语法3.4 函…

CUDA----window更新升级cuda版本

在安装库的过程中发现cuda版本不匹配。我torch安装的是11.7&#xff0c;但是我电脑上安装的是11.2故想升级。 但是我用nvidia-smi命令查询cuda是12.2&#xff0c;这让我费解&#xff0c;后来发现是得使用nvcc -V来查询安装的cuda版本。 详细的升级过程可以看这篇博客&#xff…

Android约束布局ConstraintLayout的Guideline,CardView

Android约束布局ConstraintLayout的Guideline&#xff0c;CardView <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:a…

C++ 类和对象篇(八) const成员函数和取地址运算符重载

目录 一、const成员函数 1. const成员函数是什么&#xff1f; 2. 为什么有const成员函数&#xff1f; 3. 什么时候需要使用const修饰成员函数&#xff1f; 二、取地址运算符重载 1. 为什么需要重载取地址运算符&#xff1f; 2. 默认取地址运算符重载函数 3. 默认const取地址运…