C++初阶(长期更新)第3讲:类和对象(中)

C++初阶(长期更新)第3讲:

类和对象(中)

++跟着潼心走,轻松拿捏C++,困惑通通走,一去不回头~欢迎开始今天的学++ ++习内容,你的支持就是博主最大的动力++ 。博主主页:潼心1412o-CSDN博客


前言

今天继续学习的类和对象,gogogo,出发喽~

3.1 类的默认成员函数

用户没有显式实现,编译器自动生成的成员函数。

一个类默认生成的成员函数有6个,我们重点学习前4个

三类分别为:

初始化和清理:构造函数、析构函数

拷贝复制:拷贝构造、赋值重载

取地址重载(不做讲解)

3.2 构造函数

对象实例化时初始化对象,本质为代替Init函数功能

特点:

1.函数名与类名相同

2.无返回值

3.对象实例化系统自动调用对应构造函数

4.可以重载

5.没有显式定义,C++编译器会自动生成无参默认构造函数;显式定义则不生成

cpp 复制代码
#include<iostream>
using namespace std;

//日期类
class Date
{
public:
	//无参构造
	Date()
	{
		_year = 1;
		_month = 1;
		_day = 1;
	}
	//带参构造
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//全缺省构造
	/*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;
	d1.Print();
	Date d2(2026,9,29);
	d2.Print();
	return 0;
}

注意:Date d1无参不要带括号

带括号会被当做函数声明报错类似Date func();

对象实例化一定会调用对应构造,保证对象实例化出来一定被初始化

不写构造系统会生成无参的默认构造,注意带参的无法调用

6.无参构造、全缺省构造、不显式定义编译器默认生成的构造都叫默认构造函数,但不可同时存在

不传参就可以调用的就是默认构造

无参构造和全缺省构造虽然构成函数重载但调用会存在歧义,因为全缺省同样可以不传参调用

7.编译器默认生成构造 对于内置类型,初始化没有要求,是否初始化不确定

对于自定义类型,默认构造要求调用成员变量的默认构造函数初始化

VSCode默认生成的无参构造如图,存放随机值

cpp 复制代码
#include<iostream>
using namespace std;、

//栈类
typedef int STDatatype;
class Stack
{
public:
	Stack(int n=4)
	{
		STDatatype* temp = (STDatatype*)malloc(sizeof(STDatatype) * n);
		if (temp == nullptr)
		{
			perror("malloc fail!");
			return;
		}
		_a = temp;
		_capacity = n;
		_top = 0;
	}
private:
	STDatatype* _a;
	size_t _capacity;
	size_t _top;
};

//两个Stack实现队列
class MyQueue 
{
public:
//编译器默认生成构造,调用成员变量Stack的构造函数
private:
	Stack pushst;
	Stack popst;
};

int main()
{
	Stack s1;
	MyQueue q1;
	return 0;
}

3.3 析构函数

析构函数不是销毁对象,而是完成对象中需要动态申请的资源的清理释放工作。

销毁对象比如说局部对象存在栈帧上,函数结束栈帧销毁,自动释放,对象销毁。与析构函数功能需区别开来

析构函数本质类似于Destory函数

特点:

1.函数名为 ~类名

2.无返回值
3.⼀个类只能有⼀个析构函数。若未显式定义,系统会⾃动⽣成默认的析构函数

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

5.类中没有申请资源时,析构函数可以不写,直接使⽤编译器⽣成的默认析构函数,如Date;如 果默认⽣成的析构就可以⽤,也就不需要显⽰写析构,如MyQueue;但是有资源申请时,⼀定要 ⾃⼰写析构,否则会造成资源泄漏,如Stack
6.⼀个局部域的多个对象,C++规定后定义的先析构

cpp 复制代码
~Stack()
{
	cout << "~Stack()" << endl;
	free(_a);
	_a = nullptr;
	_capacity = _top = 0;
}

增加上面这段代码运行结果如下

3.4 拷贝构造函数

一个构造函数的第⼀个参数是⾃⾝类类型的引⽤,且任何额外的参数都有默认值,则此构造函数
也叫做拷⻉构造函数,也就是说拷⻉构造是⼀个特殊的构造函数。
特点:
1.拷贝构造函数是构造函数的重载
2.第一个参数必须是类类型对象的引用,直接传值会报错,语法逻辑上会引起无穷递归。因为传值调用本身就会调用拷贝构造(见3);可以有多个参数,除第一个引用,其他参数必须有缺省值
3. C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥⾃定义类型传值传参和传值返 回都会调⽤拷⻉构造完成
4.未显式定义,编译器自动生成拷贝构造函数对内置类型进行浅拷贝/值拷贝 (⼀个字节⼀个字节的拷⻉),自定义类型成员变量调用对应拷贝构造
5.写析构就要写拷贝构造

cpp 复制代码
//...class Date public
//拷贝构造
Date(const Date& d)
{
	_year = d._year;
	_month = d._month;
	_day = d._day;
}
//...
int main()
{
	Date d1;
	d1.Print();
	Date d2(2026,9,29);
	d2.Print();
	Date d3 = d1;
	d3.Print();
	Date d4(d1);
	d4.Print();
	return 0;
}
cpp 复制代码
Stack(const Stack& st)
{
	_a = (STDatatype*)malloc(sizeof(STDatatype) * st._capacity);
	if (_a == nullptr)
	{
		perror("malloc fail!");
		return;
	}
	memcpy(_a, st._a, sizeof(STDatatype) * st._top);
	_capacity = st._capacity;
	_top = st._top;
}

// Stack若不显式实现拷贝构造,⽤自动生成的拷贝构造完成浅拷贝

// 会导致s1和s2⾥⾯的_a指针指向同⼀块资源,析构时会析构两次,程序崩溃

//MyQueue⾃动⽣成的拷⻉构造,会⾃动调⽤Stack拷⻉构造完成pushst / popst

// 的拷⻉,只要Stack拷⻉构造⾃⼰实现了深拷⻉,他就没问题


++好了今天的学习内容就到这里啦,谢谢你的陪伴,我是潼心,下次再见~如果这篇文章对你有帮助的话。请务必给主播一个一键三连,球球了,这对主播很重要~++

博主主页:潼心1412o-CSDN博客

相关推荐
Pin_Qing9 小时前
账单没超,请求先被拒了
大数据·开发语言·人工智能
2601_962885729 小时前
如何用 Python 计算 VaR 和 CVaR(在险价值)?
开发语言·python
郝亚军9 小时前
manifest 中 `sha256` 与 `signValue` 的作用
java·开发语言·数据结构
syagain_zsx9 小时前
jsoncpp 使用指南:编译链接、Json::Value 取值与高频坑
c++·json·库·http格式
譕痕9 小时前
stripe 实例
java·开发语言·stripe·checksession
墨子夕10 小时前
设计模式——Java × Python 双语言精讲 · 23 个经典模式 + 现代演进(前言篇)
java·开发语言·设计模式
_菜鸟果果10 小时前
高德地图 JS API 2.0 在国产 Linux/ARM 电脑上渲染失败 的排查与解决
linux·开发语言·javascript
布莱克60510 小时前
理解 = delete 与 = default:两种赋值语义的差异
c++
昂好的day10 小时前
VisionMaster(VM) 标定工具详解(上):为什么必须标定 + 九点标定手眼标定
开发语言·数码相机·c#
严谨的麻辣烫10 小时前
静态代理 IP 的出口一致性如何验证?Python 请求检测与异常排查
开发语言·python·http·网络安全