C++初阶(长期更新)第3讲:
类和对象(中)
跟着潼心走,轻松拿捏C++,困惑通通走,一去不回头~欢迎开始今天的学习内容,你的支持就是博主最大的动力。
博主主页:潼心1412o-CSDN博客
前言
今天继续学习的类和对象,gogogo,出发喽~
3.1 类的默认成员函数
用户没有显式实现,编译器自动生成的成员函数。
一个类默认生成的成员函数有6个,我们重点学习前4个
三类分别为:
初始化和清理:构造函数、析构函数
拷贝复制:拷贝构造、赋值重载
取地址重载(不做讲解)
3.2 构造函数
对象实例化时初始化对象,本质为代替Init函数功能
特点:
1.函数名与类名相同
2.无返回值
3.对象实例化系统自动调用对应构造函数
4.可以重载
5.没有显式定义,C++编译器会自动生成无参默认构造函数;显式定义则不生成
#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默认生成的无参构造如图,存放随机值
#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.无返回值
4.对象生命周期结束,系统自动调用对应析构函数
5.类中没有申请资源时,析构函数可以不写,直接使⽤编译器⽣成的默认析构函数,如Date;如 果默认⽣成的析构就可以⽤,也就不需要显⽰写析构,如MyQueue;但是有资源申请时,⼀定要 ⾃⼰写析构,否则会造成资源泄漏,如Stack
~Stack() { cout << "~Stack()" << endl; free(_a); _a = nullptr; _capacity = _top = 0; }增加上面这段代码运行结果如下
3.4 拷贝构造函数
//...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; }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博客