在c++的类中,就算我们什么成员函数都不写,也会有六个自动生成的默认成员函数,分别是
- 构造函数:来完成对象的初始化
- 析构函数:来进行清理
- 拷贝构造:通过同类对象来初始化对象
- 赋值重载:把一个对象赋值给另一个对象
- 两个取地址操作符重载
构造函数
我们以简单的日期类举例,上篇文章中我们在日期类中写了一个成员函数Init来完成日期的初始化,但是如果我们每次创建完对象之后都要调用它的Init函数来初始化的话,有点太麻烦了,我们能不能像int a=1;一样在创建对象的时候就把信息填进去呢?
当然是可以的,那就是构造函数,它的名字和类名一样,没有返回值,在创建对象的时候会自动调用,下面就给一个自己写的构造函数
Date(int year = 1970, int month = 1, int day = 1)
{
if (year > 0 && (month > 0 && month < 13) && (day > 0 && day < 32))
{
_year = year;
_month = month;
_day = day;
}
else
cout << "非法参数" << endl;
}
int main()
{
Date a;
Date b(2022,5,23);
}
无参的或是全缺省的构造函数,也包括我们不写编译器自动生成的都可以叫默认构造函数,默认构造函数只能有一个
可以看到我们创建对象a时没有给参数,他就会填入缺省参数,变成1970年1月1日,而b则是2022年5月23日
如果我们不写这个构造函数的话编译器会自动生成一个构造函数,它不会对基本数据类型进行处理,对于自定义类型会去调用它的构造函数,就是说如果我们的日期类里面还有一个成员变量class A,那么我们的默认构造函数会让年月日是随机值,并且调用class A的构造函数对A进行初始化
析构函数
析构函数要做的是去清理对象需要的资源
它的函数名就是类名加上~,就像~Date,没有参数也没有返回值,如果我们不自己写,编译器会自动生成一个,在对象的生命周期结束时,会自动调用析构函数
析构函数在日期类上并不需要,日期类里的int就像一个我们在main函数中定义的int类型一样除了main函数就销毁了,它需要做的是如果我们malloc了空间,我们要在析构函数中free这些空间,并将指针制空
如果我们没有写析构函数,那么和构造函数一样,编译器会默认生成一个,这个默认的析构函数的作用也和构造函数一样,对于基本数据类型不做处理,对于自定义类型,调用它的析构函数
拷贝构造
如果我们创建对象b时想让他和a一模一样怎么办,就需要我们的拷贝构造,拷贝构造是构造函数的重载,他的参数是对本类对象的引用,使用传值构造会出问题,因为函数传参实际上是对参数进行拷贝,而对参数拷贝就要调用拷贝构造,会一直调用拷贝构造
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
至于默认生成的拷贝构造,他会进行浅拷贝,也就是值拷贝,这样的拷贝在日期类中没有问题,但是如果有一个类需要malloc一个数组,并存下它的地址p,在只拷贝的时候这个地址p会被拷贝过来,两个对象会共用同一个数组,这个时候就需要用到深拷贝,这个之后再讲
运算符重载
类对象也可以使用运算符进行加减大于小于等运算符进行运算的,只需要在类中对运算符进行重载并写好它的实现逻辑即可,他需要写成以下逻辑
返回值类型 operator(参数)
{
实现逻辑;
}
需要注意的是.* 、:: 、sizeof 、?: 、. 这五个运算符不能重载
就比方我们先重载一个简单的==
bool operator==(const Date& d)
{
return ((_year == d._year) && (_month == d._month) && (_day == d._day));
}
可是==明明有两个参数,左边的对象和右边的对象,为什么我们只传了一个呢,那是因为它还有一个隐藏的参数,一个this指针,这个this指针才是函数的第一个参数,我们_year都应该看作this-> _year,我们在重载赋值运算符时返回的就是这个this指针的解引用
Date operator=(const Date& d)
{
if (this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
return *this;
}
赋值运算符的重载也是类的默认成员函数,我们如果不重载,编译器会自己生成,实现逻辑也和默认的拷贝构造一样,进行浅拷贝
取地址操作符重载
这两个默认成员函数在大部分情况下都不需要我们自己去写,如果我们自己写实现逻辑如下
Date* operator&()
{
return this ;
}
const Date* operator&()const
{
return this ;
}
我们可以看到第二个成员函数的后面有const,这个叫const成员函数,实际上是拿来修饰this指针的,但是this指针不能写在参数里,因此把const写在括号后面,作用是保证类的成员不被修改