【C++】类的默认成员函数(上)
🔥博客主页: 小���失眠啦.
🎥系列专栏:《C语言》 《数据结构》 《C++》 《Linux》 《Cpolar》
❤️感谢大家点赞👍收藏⭐评论✍️
文章目录
- 一、默认成员函数
- 二、构造函数
- 构造函数的概念及特性
- 三、析构函数
- 析构函数的特性
- 四、拷贝构造函数
- 拷贝构造函数的特性
一、默认成员函数
上一章中我们谈到,如果一个类中什么成员也没有,那么这个类就叫作空类。其实这么说是不太严谨的,因为一个类不可能什么都没有。
当我们定义好一个类,不做任何处理时,编译器会自动生成以下6个默认成员函数:
- 默认成员函数:如果用户没有手动实现,则编译器会自动生成的成员函数。
- 构造函数:主要完成初始化工作;
- 析构函数:主要完成清理工作;
- 拷贝构造:使用一个同类的对象初始化创建一个对象;
- 赋值重载:把一个对象赋值给另一个对象;
- 取地址重载:普通对象取地址操作;
- 取地址重载(const):const对象取地址操作;
本章我们将学习四个默认成员函数——构造函数与析构函数——拷贝构造 与赋值重载
二、构造函数
在C语言阶段,我们实现栈的数据结构时,有一件事很苦恼,就是每当创建一个stack对象(之前叫作定义一个stack类型的变量)后,首先得调用它的专属初始化函数StackInit来初始化对象。
typedef int dataOfStackType; typedef struct stack { dataOfStackType* a; int top; int capacity; }stack; void StackInit(stack* ps); //... int main() { stack s; StackInit(&s); //... return 0; }
这不免让人觉得有点麻烦。在C++中,构造函数为我们很好的解决了这一问题。
构造函数的概念及特性
构造函数是一个特殊的成员函数。构造函数虽然叫作构造,但是其主要作用并不是开辟空间创建对象,而是初始化对象。
构造函数之所以特殊,是因为相比于其它成员函数,它具有如下特性:
- 函数名与类名相同;
- 无返回值;
- 对象实例化时,编译器自动调用对应的构造函数;
- 构造函数可以重载;
举例
class Date { public: //无参的构造函数 Date() {}; //带参的构造函数 Date(int year,int month,int day) { _year = year; _month = month; _day = day; } private: int _year; int _month; int _day; }; void TestDate() { Date d1;//调用无参构造函数(自动调用) Date d2(2023, 3, 29);//调用带参构造函数(自动调用) }
特别注意
- 创建对象时编译器会自动调用构造函数,若是调用无参构造函数,则无需在对象后面使用()。否则会产生歧义:编译器无法确定你是在声明函数还是在创建对象。
错误示例
//错位示例 Date d3();
- 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
class Date { public: //若用户没有显示定义,则编译器自动生成。 /*Date(int year,int month,int day) { _year = year; _month = month; _day = day; }*/ private: int _year; int _month; int _day; };
- 默认生成构造函数,对内置类型成员不作处理;对自定义类型成员,会调用它的默认构造函数;
- C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int、char、double…,自定义类型就是我们使用class、struct、union等自己定义的类型。
举例
默认构造函数对内置类型
class Date { public: //此处不对构造函数做显示定义,测试默认构造函数 /*Date() {}*/ void print() { cout Date d1; d1.print(); } public: //此处对stack构造函数做显示定义 stack() { cout public: //此处不对queue构造函数做显示定义,测试默认构造函数 /*queue() {}*/ private: //自定义类型成员 stack _s; }; void TestQueue() { queue q; } public: //... void print() { cout Date d2; d2.print(); } public: //无参的默认构造函数 //Date() //{ //} //全缺省的默认构造函数 Date(int year = 0, int month = 0, int day = 0) { _year = year; _month = month; _day = day; } void print() { cout public: Stack() { //... } void Push(int x) { //... } bool Empty() { // ... } int Top() { //... } void Destory() { //... } private: // 成员变量 int* _a; int _top; int _capacity; }; void TestStack() { Stack s; st.Push(1); st.Push(2); //过去需要手动释放 st.Destroy(); } public: Date() { cout cout Date d3; //d3生命周期结束时自动调用构造函数 } public: //此处对stack构造函数做显示定义 stack() { cout cout public: //此处不对queue构造函数做显示定义,测试默认构造函数 /*queue() {}*/ private: //自定义类型成员 stack _s; }; void TestQueue1() { queue q; } public: //构造函数 Date() { cout cout cout Date d1; //调用拷贝构造创建对象 Date d2(d1); } public: //错误示例 //如果这样写,编译器就会直接报错,但我们现在假设如果编译器不会检查, //这样的程序执行起来会发生什么 Date(const Date d) { _year = d._year; _month = d._month; _day = d._day; } private: int _year = 0; int _month = 0; int _day = 0; }; void TestDate() { Date d1; //调用拷贝构造创建对象 Date d2(d1); } public: //构造函数 Date(int year = 0, int month = 0, int day = 0) { //cout cout Date d1(2023, 3, 31); //调用拷贝构造创建对象 Date d2(d1); d2.print(); } public: stack(int defaultCapacity=10) { _a = (int*)malloc(sizeof(int)*defaultCapacity); if (_a == nullptr) { perror("malloc fail"); exit(-1); } _top = 0; _capacity = defaultCapacity; } ~stack() { cout _a[_top++] = n; } void print() { for (int i = 0; i
- 默认成员函数:如果用户没有手动实现,则编译器会自动生成的成员函数。
- 拷贝构造函数的特性
The End