✨Blog:🥰不会敲代码的小张:)🥰
🉑推荐专栏:C语言🤪、Cpp😶🌫️、数据结构初阶💀
💽座右铭:“記住,每一天都是一個新的開始😁😁😁”
💀本章内容:《C++类和对象(中)》的介绍✨
目录
- 前言
- 类的6个默认成员函数
- 构造函数
- 析构函数
- 拷贝构造
- 运算符重载
- 赋值重载
- 取地址重载
- const成员
前言
上期我们讲了C++类和对象(上)
类的6个默认成员函数
如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
用白话来说就是:我们不写,编译器会自己生成
构造函数
- 函数名与类名相同。
- 无返回值。
- 对象实例化时编译器自动调用对应的构造函数。
- 构造函数可以重载。
class Date
{
public://构造Date(){_year = 1;_month = 1;_day = 1;}//构造函数可以重载,如果这里给成全缺省值,和上面的构造也构成重载,但是如果在实例化时不传参,会造成调用不明确Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
如果类中没有显示定义构造函数,则C++编译器会自动生成一个无参默认构造函数,内置类型不做处理,自定义类型会去调用他的默认构造
如何理解上面这句话呢,下面我们来看一段代码
内置类型:
自定义类型:
1.一般情况下,有内置类型成员,就需要自己写构造函数,不能用编译器自己生成
2.如果都是自定义类型成员,可以考虑让编译器自动生成构造函数
如:OJ题,用两个栈实现队列
但是归根结底最开始的自定义类型类型还是自己写了构造函数
结论:
1.一般情况下,构造函数都需要自己写
2.什么情况下不需要写呢?
a.内置类型成员都有缺省值,且初始化符合我们的要要求
b.全是自定义类型,且这些类型都定义了默认构造
可以在类型声明的时候给缺省值:
如果我们没有显示传递值,那么编译器就会使用默认缺省值,相当于备胎
析构函数
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
- 析构函数名是在类名前加上字符 ~。
- 无参数无返回值类型。
- 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
- 对象生命周期结束时,C++编译系统系统自动调用析构函数。
这里我们只演示自定义类型是不是会去调用它自己的析构:
- 一般情况下,有动态内存申请的,就需要显示写析构函数释放资源
- 没有动态资源申请,不需要写析构
- 需要释放的对象成员都是自定义类型,不需要写析构
拷贝构造
在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎
- 拷贝构造函数是构造函数的一个重载形式。
- 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
C++规定内置类型传参是直接拷贝,自定义类型传参是先调用拷贝构造完成拷贝。
内置类型:我们不写编译器自己生成,内置类型成员完成值拷贝/浅拷贝
**自定义类型:**自定义类型成员会调用它的拷贝构造
如果要拷贝构造的函数中有malloc出来的空间,需要自己定义深拷贝,否则会指向同一块空间,析构函数就会调用两次,程序就会崩,另外一个问题就是,一个修改,会影响另外一个。
运算符重载
日期-日期//有意义
日期+日期//没意义
是否要运算符重载,取决这个运算符对这个类是否有意义
- 操作符有几个操作数,重载函数就有几个参数
- operator后加操作符
.* :: sizeof ?: . 这五种运算符不能构成重载
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}bool operator<(const Date& d){if (_year < d._year){return true;}else if (_year == d._year && _month < d._month){return true;}else if (_year == d._year && _month == d._month && _day < d._day){return true;}else{return false;}}private:int _year;int _month;int _day;
};int main()
{Date d1(2023, 2, 3);Date d2(2024, 2, 3);bool ret = d1 < d2;//自定义类型比较大小,会去调用运算符重载cout << ret << endl;return 0;
}
iostream头文件包含ostream和istream,ostream包含operator自定义类型运算符重载,而cout就是调用operator<<函数重载自动匹配内置类型,我们之所以可以使用内置类型比较大小,是因为内置类型是库里面已经实现的。
赋值重载
已经存在的两个对象之间复制拷贝
编译器自己生成的赋值重载,只能完成浅拷贝,如果有malloc出来的对象,需要自己写赋值重载。
默认生成的赋值重载跟拷贝构造是一样的
1.内置类型———值拷贝/浅拷贝
2.自定义类型成员会去调用它的赋值重载
取地址重载
在平常内置类型可以直接使用取地址运算符,但是自定义类型不可以,不过系统会自动生成默认函数,平时默认的就足够使用。
const成员
将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
void Print()const
==
void Print(const Date*this)
但是this指针是隐式的,不能显示修改,所以直接在括号后面加上const。
bool operator==(const Date& d) const//修饰的是*this
{return _year == d._year&& _month == d._month&& _day == d._day;
}
加上const以后,普通对象和const对象都可以掉用,普通对象调用加上const函数,权限缩小
权限缩小可以,但是不能权限放大。
如果没有加上const,而实例化对象是const,则不能正常调用,因为权限可以平移,可以缩小,但是不能放大。
结论:
- 要修改的对象成员函数不能加const
- 只要成员函数内部不修改,都应该加上const
因为这样const对象和普通对象都可以调用