前言:本篇文章是对六大默认成员函数的自我总结,不适合刚入门的新人学习。适合想进一步深入了解六大默认成员函数的人学习。
1.构造函数:给对象初始化的函数,相当于之前写的Init函数。
构造函数的特性:
对内置类型不做处理(也可处理,取决于编译器),对自定义类型:去调用它的默认构造函数(下面会提到默认构造函数包括哪几类)。
不写返回值
函数的名字就是类名
可以函数重载(不同的初始化方式)
对对象初始化
string Date
{
public:
Date(int year=1;int month=1;int day=1)
{
int _year=year;
int _month=month;
int _day=day;
}
private:
int _year;
int _month;
int _day;
}
这一段代码写了构造函数:没有返回值,函数名就是Date,全缺省,赋初值。
string Date
{
public:
Date(int year=2024;int month=4;int day=26)
{
int _year=year;
int _month=month;
int _day=day;
}
private:
int _year=1;
int _month=1;
int _day=1;
}
这一段代码,多了一个缺省值,注意,int _year=1;int _month=1;int _day=1这里是声明,不是定义。
这一段代码,会先走int _year=1;int _month=1;int _day=1这一段,然后再进入构造函数体内部。
整体的进行过程,先把年月日用缺省值的1,然后进入函数体内部,在对年月日赋初值。
(注意:如果有初始化列表,就不会走缺省值)
//构造函数
Date(int year = 1, int month = 1,int day=1)
:_year(year)
,_month(month)
,_day(day)
{}
有初始化列表,就不会走缺省值那一条路。
默认构造函数:
1.无参的
2.全缺省的
3.编译器自动生成的
(为什么要有默认构造函数这个概念?-->对于自定义类型,会去调用它的默认构造函数)
注意点:
没有写构造函数,写了拷贝构造-->编译器就不会自动生成构造函数(对内置类型:不做处理。对自定义类型:调用对应的构造函数)
写了构造,没写拷贝构造-->编译器会自动生成拷贝构造(对内置类型:浅拷贝,值拷贝。对自定义类型:调用类对象的拷贝构造)
2.析构函数:
特点:
1.函数名前面加~
2.函数名就是类名
3.不需要传参
4.一个类里面只能写一个析构函数
5.析构函数是资源的清理,而不是销毁数据
3.拷贝构造:
特点:
1.需要传引用传参(否则会发生无穷递归:传自定义类型需要调用对应的拷贝构造)
2.没有返回值
3.拷贝的对象和被拷贝的对象的类型一致
4.对于内置类型:浅拷贝
5.对于自定义类型:调用类的拷贝构造(所以如果不是传引用传参,会发生无穷递归)
6.拷贝构造也可以写初始化列表,也会去走缺省值的地方
Date(Date& d)
{
_year=d._year;
_month=d._month;
_day=d._day;
}
拷贝构造的使用:
Date d1(2024,4,26);
Date d2(d1);//拷贝构造
Date d2=d1;//拷贝构造(注意注意,这里是拷贝构造)
区分:
拷贝构造和赋值重载
Date d1=d2;//拷贝构造
d1=d2;//赋值重载
拷贝构造是一个特殊的构造函数,构造-->初始化对象,拿d2的值去初始化d1
赋值重载,是两个已经存在的对象,拿d2的值去赋给d1。把d1原来的值覆盖掉。
运算符重载:
1.这一类的函数的返回值和参数是和运算符的类型有关的。
1. bool operator<(const Date& d1,const Date& d2);
2. Date operator+=(int day); //里面可以是内置类型
3. int operator--(const Date& d1,const Date& d2);
2.运算符重载中必须要有一个自定义类型。
3.如果写成成员函数,参数要少一个。
4.下面5中运算符不能重载 .*(点星) ::(域限定符) sizeof ?:(三目运算符) .(对象点)
5.如果成员函数和全局的同时存在,会先去调用成员函数的。那时候全局的就没有意义了。
如果类里面没有,就会去全局中找。找不到就报错。
6.前置++ Date& operator++()
后置++ Date& operator++(int) 规定后置++多一个int参数,这个参数只是为了识别前置后置
(不能double,char,只是为了让编译器区分)
//前置++
Date& operator++()
{
*this += 1;
return *this;
}
//后置++
Date operator++(int)
{
Date tmp(*this);
*this += 1;
return tmp;
}
对于自定义类型,后置++的消耗更大,拷贝构造tmp变量 ,然后又传值返回
4.赋值重载:
把=这个运算符进行重载,让它可以运用在自定义对象里面。
赋值重载的函数的返回值可以是void,但是我们通常这样子写。
Date& operator=(const Date& d1)
{
_year=d1._year;
_month=d1._month;
_day=d1._day;
return *this;
}
1.代码的意思?
把d1的值赋给this指针指向的变量,然后再返回*this,让*this作为下一个赋值的右操作数。
就形成了练习赋值。
2.为什么要写成Date&
因为要支持连续赋值。
3.为啥要传引用返回?
不用创建临时变量(临时变量需要调用拷贝构造),传引用返回-->别名
临时变量具有常性。
4.注意点:规定赋值重载不能写成全局的。其他重载可以。
拷贝构造和赋值重载:
对于内置类型:按字节拷贝(赋值)
对自定义类型:会去调用它的拷贝构造(赋值重载)
5.取地址重载:
对取地址符号进行重载,让它可以对自定义类型的对象进行取地址。
默认生成就够用了,一般情况下不需要我们自己重新写。
class Date
{
public:
Date* operator&() //就只有一个参数this
{
return this;
}
private:
int _year;
int _month;
int _day;
}
Date d1;
cout<<&d1;
6.const取地址重载:
对于const修饰的自定义类型,也重载了并且编译器自动生成。
返回类型要加const,对this也加const
class Date
{
public:
const Date* operator&() const //就只有一个参数this
{
return this; //返回的this是不可以修改的,所以返回类型加了const
}
private:
int _year;
int _month;
int _day;
}
const Date d1;
cout<<&d1;
对于取地址重载和const修饰的取地址重载,平时我们不需要管它,只需要我们可以用来对自定义类型的对象进行取它的地址就可以了。 我们不需要显示的写。