类中,默认生成六个成员函数:
- 构造函数
- 拷贝构造函数
- 析构函数
- 赋值运算符重载
- 取地址(&)运算符重载
- const修饰的取地址运算符重载
构造函数
class Date
{
public:
Date()
{
_year = 0;
_month = 0;
_day = 0;
}
private:
int _year;
int _month;
int _day;
};
构造函数是一个特殊的成员函数,是在创造类类型对象,对象被实例化时,由编译器自动调用。
构造函数名字与类名相同,不能由用户自主命名,没有类型,没有返回值。
在对象的生命周期内只且只调用一次,以保证每个数据成员都有一个合适的初始值。它不能被用户调用,且没有this指针。
构造函数有初始化列表,可以进行初始化也可以不进行。
构造函数功能是由用户自己定义的,用户根据初始化的要求设计函数体和函数参数。
用户如果没有自己定义构造函数,则系统会自动生成一个空的默认构造函数,不执行任何操作,但是仍然会被调用。
初始化列表
除了在函数体内初始化的方式之外,还可以在函数首部,通过初始化列表对数据成员实现初始化。
初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
,_day(day)
{
}
private:
int _year;
int _month;
int _day;
};
为何会有这种方法?
有些数据成员,例如用const修饰的变量必须在创建的时候进行初始化,所以只能通过初始化列表进行初始化,而且这种方法比较高效。
带参构造函数
在定义对象时,希望给不同的对象赋予不同的初始值。
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2017, 3, 19);
Date d2(1970, 1, 1);
system("pause");
return 0;
}
构造函数重载
类中可以包含多个构造函数,即构造函数可重载。
在建立类对象时,只执行其中一个构造函数。
- 最好在声明构造函数时指定默认值,而不能只在定义构造函数时指定默认值。
- 在一个类中定义了全部是默认参数的构造函数后,不能再定义重载构造函数。
- 无参合全缺省构造函数均为缺省构造函数。
- 构造函数不能用const修饰,一旦使用const修饰,则不能给成员赋值,失去意义。
- 构造函数其实是有返回值的,返回this指针。
- 用explicit修饰构造函数,抑制由构造函数定义的隐式类型转
换。
explicit关键字需要放置在类中构造函数的声明上,在类外构造函数的定义体中不需要再写。
拷贝构造函数
拷贝构造函数就是由一个已有的对象复制出多个完全相同的对象。是构造函数的重载。
拷贝构造函数只有单个形参,而且该形参是对本类类型对象的引用(常用
const修饰)。
拷贝构造函数是特殊的构造函数,创建对象时使用已存在的同类对象来进
行初始化,由编译器自动调用。
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
,_day(day)
{
}
Date(const Date& d)
{
_year = d.year;
_month = d.month;
_day = d.day;
}
private:
int _year;
int _month;
int _day;
};
拷贝构造函数必须使用同类型对象的引用传递,为什么呢?
如果不是引用的话,会引发无穷的递归。
什么时候用拷贝构造函数
当程序中需要建立一个新的对象,而这个新的对象是用另一个对象初始化它。
Date d1(2017, 3, 19);
Date d2(d1);
当函数的参数是类的对象时。在调用函数时需将实参对象完整地传递给形参,也就是需要建立一个实参的拷贝。
void test(const Date d)
{
}
当函数的返回值是类的对象时。函数调用完毕将返回值带回时,需要将函数中的对象拷贝一个临时对象返回。
Date test()
{
Date d;
return d;
}
析构函数
析构函数的作用与构造函数相反。定义格式为在类名前面加上取反(~)符号。
析构函数无参数无返回值。在对象释放前调用。
未定义析构函数则系统会自动生成缺省的析构函数。
1、析构函数的作用并不是删除对象,而是在撤销对象时做一些清理工作。比如关闭打开的文件,释放开辟的动态内存等工作。
2、析构函数不返回任何值,没有函数类型,没有参数,因此也不能重载。
3、调用构造函数和析构函数的顺序:
因为函数压栈的关系,所以先构造的后析构,后构造的先析构。如果有全局对象或者静态局部对象,则它们在main函数结束或者调用exit函数时2被析构。
赋值运算符重载
同一类中的两个或多个对象之间可以相互赋值,即一个对象中的所有数据成员可以赋予另一个同类的对象。这时赋值运算符普通的功能已经无法满足使用,因此便有了赋值运算符的重载。
对象之间的重载也是通过赋值运算符“=”来实现。
赋值运算符重载和拷贝构造函数功能不同,赋值运算符时对一个已经创建的对象赋值。
使用赋值运算符时,类的数据成员中不能包括动态分配的数据。否则在析构时会将同一块内存释放多次。
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
,_day(day)
{
}
Date operator=(Date& d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
取地址(&)运算符重载
const修饰的取地址运算符重载
class Date
{
public:
Date(int year, int month, int day)
: _year(year)
, _month(month)
,_day(day)
{
}
const Date* operator&()const
{
return this;
}
private:
int _year;
int _month;
int _day;
};