【C++】【类与对象超强知识汇总】(三)

本文详细介绍了C++类的6个默认成员函数。包括构造函数用于初始化对象,析构函数完成资源清理,拷贝构造函数实现对象拷贝,赋值运算符重载解决自定义类型运算问题,const成员函数保护成员不被修改,取地址及const取地址操作符重载一般无需自定义。还探讨了各函数的特性、使用场景及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


前情提要,本章涉及的知识点较多,建议收藏慢慢消化

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


类的6个默认成员函数

但一个函数中什么成员都没有,那么我们就叫它空类

在这里插入图片描述

  • 但是空类里面真的什么都没有嘛?
  • 其实并不是,任何类在什么都不写的时候,编译器会自动生成一下六个默认成员函数

以下为六个默认成员函数👇

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/e7407550a9524bf1abe5417fcef3bea1.png

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


一、 构造函数

  • 概念

我们在用C写栈的时候,是否经常会遇到初始化的问题而导致程序崩溃。忘记调用 Init 就使用,那么下面的构造函数就能很好的解决我们的问题。

int main()
{
   
    //忘调用Init 就使用
    Date d1;
    Date d2;
    d1.Print();
    d2.Print();
}

在这里插入图片描述

  • 这个时候就很有构造函数的必要了!
    在这里插入图片描述

  • 构造函数可以重载也就代表有多种初始化方式
    比如一下两种:
    在这里插入图片描述

  • 让我们来运行一下看看结果:
    在这里插入图片描述在这里插入图片描述

  • 虽然可以构造函数,但是一般情况下,一般建议每个类都可以写一个全缺省函数。

请添加图片描述

在这里插入图片描述

  • 特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
务并不是开空间创建对象,而是初始化对象。

其特征如下:

1. 函数名与类名相同
2. 无返回值
3. 对象实例化时编译器自动调用对应的构造函数
4. 构造函数可以重载

在这里插入图片描述

在这里我们使用日期函数来举例子:
在这里插入图片描述

  • 此时我们在用main函数实行的时候发现,欸嘿,完成初始化了!
    在这里插入图片描述
    在这里插入图片描述
  • 在这里,没有调用Init函数,却没有崩!
    在这里插入图片描述
  • 欸?那有一个问题,如果我们不写构造函数,结果又会是什么呢?
    在这里插入图片描述
    糟了…怎么会是随机值呢!
    在这里插入图片描述
    不要慌哈!C++ 在这里给我们的数据类型分为两个部分。

在这里插入图片描述
既然这样,那我们加上一个自定义类型尝试一下。

请添加图片描述
在这里插入图片描述

int main()
{
   
	Date d1;
	d1.Print();

	return 0;
}

请添加图片描述

  • 然后我们又扯出一个非常重要的知识点:默认构造函数

不实现构造函数的情况下,编译器会生成默认的构造函数。在这里插入图片描述

  • 问题一 ,当我们这样改动的话,他还是构造函数吗?
    在这里插入图片描述
    这个时候,没有构造函数,编译器就报错啦!

  • 总结:不传参数就可以调用默认构造函数
    在这里插入图片描述
    所以,在上面传参后,Date _t 不具备默认构造函数

  • 无参构造函数, 全缺省构造函数, 我们没写编译器默认生成的构造函数,都可以认为是默认构造函数->基本上只能存在一种

对此我们对应的方法就是:给缺省值:就是这样!👇
这个也是C++后期打补丁添加的

在这里插入图片描述

  • 在这里就是声明, 并不是初始化

在这里插入图片描述
总结:

  1. 一般情况下,构造函数都需要我们自己显示的去实现
  2. 只有少数的情况下, 可以让编译器自动生成构造函数

二、析构函数

  • 概念

对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

  • 我们在开辟空间后,常常又会忘记调用 Destory 函数

  • 这样的结果往往会导致内存泄漏,析构函数由而诞生

  • 像上面的Date函数是不需要析构函数的,因为没有开辟新的空间,故而没有资源需要清理

在这里插入图片描述

  • 特性
    析构函数时特殊的成员函数,其特征如下:
  1. 析构函数名是在类名之前加上字符 ~
  2. 无参数无返回值类型
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 在函数生命周期结束前自动调用!

在这里插入图片描述

  • 代码如下👇:
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()  //析构函数
	{
   
		cout << "~Stack()" << endl; // 这里打印出是为了更好的看出是否调用
		if (_array)
		{
   
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};

欸!我们运行一下,发现析构函数和构造函数都打印出来了,说明该运行过程中调用了该成员函数

在这里插入图片描述

  • 这里说明了析构函数是可以自动调用的!

在这里插入图片描述

在实践中总结:
1. 资源中需要显示清理,就需要写析构,如:Stack List
2. 有两种场景不许呀显示写析构函数,默认生成就可以了
a 没有资源需要清理,如: Date
b 内置类型成员没有资源需要清理,剩下都是自定义类型成员。如: MyQueue
在这里插入图片描述


在这里小小的总结一下哈:

  1. 构造函数就是初始化函数
  2. 析构函数就是销毁函数
    在这里插入图片描述

三、拷贝构造函数

  • 概念

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

在这里插入图片描述
拷贝构造也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
  4. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了
    在代码上是这样实现的👇
    在这里插入图片描述
  • 这样是可以进行成功的赋值,但是需要注意的一点是
//当初始化为一下这种形式时,会发生无穷递归
Date(Date d)
{
   
    _year = d._year;
    _month = d._month;
    _day = d._day;
}
//为什么呢?
  • 知识点:传自定义类型的传值传参需要调用拷贝构造完成

调用func得先传参,自定义类型对象传参要调用拷贝构造函数完成

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Reuuse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值