1.构造函数。
2.析构函数。
3.拷贝构造函数。
4.赋值运算符重载。
5.取地址运算符重载(非const)。
6.取地址运算符重载(const)。
class Date
{
public:
Date(); //构造函数
~Date(); //析构函数
Date(Date &); //拷贝构造函数
Date & operator=(const Date &d); //赋值运算符重载
Date * operator&(Date d); //取地址运算符重载
const Date * operator&(Date d)const; //取地址运算符重载
};
Date d1; //调用构造函数
Date d2(d1); //调用拷贝构造函数
Date d3;
d3 = d1; //调用赋值运算符重载
Date *d4 = &d1; //调用取地址运算符重载(非const)
const Date*d5 = &d1; //调用取地址运算符重载(const)
C++编译器对这些函数的实现
Date()
{
}
~Date()
{
}
Date(Date &)
{
}
Date & operator=(const Date &d)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if (this != &d)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>return *this;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
Date * operator&(Date d)
{
return this;
}
const Date * operator&(Date d)const
{
return this;
}
构造函数
构造函数是来处理对象的初始化。构造函数是一种特殊的成员函数,不需要用户来调用它,而是在建立对象时自动执行。
【构造函数特性】
1.函数名与类名相同,没有返回值。
2.构造函数不需要用户调用,也不能被用户调用,在建立对象时编译器会自动调用,在对象的生命周期内只调用一次。
3.如果用户没有显示定义构造函数,C++系统会自动生成一个构造函数。
4.构造函数可以重载。
5.无参的或者全缺省的构造函数称作默认构造函数,一个类中只能有一个默认构造函数。
Date(int year=1990,int month=1,int day=1) //声明一个全缺省的默认构造函数
{
_year=year;
_month = month;
_day = day;
}
Date() //声明一个无参的默认构造函数
{
}
在建立对象时如果写成
Date d1;
编译系统就无法识别应该调用哪个构造函数,出现歧义性,编译时报错。
【构造函数的作用】
1.创建对象
2.初始化成员列表
3.隐式类型转换
析构函数
析构函数的功能与构造函数的功能相反,在已创建的对象销毁时,编译器自动调用析构函数来完成一些资源清理。
【析构函数特性】
1.没有返回值,没有参数,不能重载。
2.一个类有且只有一个析构函数,调用几次构造函数,则调用几次析构函数。
3.先构造的对象后析构,后构造的对象先析构。
何时自动执行析构函数:
1.在函数内部创建的对象,当这个函数调用结束时,自动执行析构函数释放该对象。
2.static局部对象在函数调用结束时并不释放,也不调用析构函数,而是在main函数结束时才调用static对象的析构函数。
3.全局的对象在main函数结束时,调用全局对象的析构函数。
4.用new动态创建的对象,在用delete释放该对象时,调用该对象的析构函数。
注意:析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使这部分内存可以被程序分配给新对象使用。
拷贝构造函数
拷贝构造函数是用来用已有对象创建一个新对象以,然后将已有对象的值一一赋给新对象 ,同样由编译器自动调用。
【析构函数特性】
1.只有一个参数,且类型为类类型的引用,常用const修饰(防止创建临时对象时无限递归,导致堆栈溢出)。
2.它是构造函数的重载。
3.如果没有显示定义,编译器会自动合成一个默认的拷贝构造函数。
何时调用拷贝构造函数:
1.用已有对象初始化建立一个新对象时:
Date d1(2001,1,1);
Date d2(d1);
2.当函数的参数为类的对象时。在实参传递给形参时,创建一个实参的临时拷贝,然后赋给形参,此时调用拷贝构造函数。
void Test(Date d)
{
}
int main()
{
Date d1(2000, 1, 1);
Test(d1);
}
3.函数的返回值是类的对象时。在函数调用完时,创建一个返回值的临时对象,然后传给该函数的调用处。
Date Test()
{
Date d2(2001, 1, 1);
return d2;
}
int main()
{
Date d1;
d1 = Test();
}
注意:对象的赋值与对象的拷贝的不同。赋值是将一个已有对象的数据赋给另一个已有对象的成员,而拷贝是从无到有的建立一个新对象。
int main()
{
Date d1(20021, 1, 1);
Date d2(d1); //拷贝,调用拷贝构造函数。 不调用d2的构造函数。
Date d3; //调用d3的构造函数。
d3 = d1; //赋值,调用赋值运算符重载函数,不调用拷贝构造函数。
}
赋值运算符重载
对于赋值运算符重载函数有三个值得注意的地方:
1.返回值为类类型的一个引用。
这是为了解决出现连续赋值的问题。
2.参数类型为const修饰的类类型的引用。
用const修饰是防止函数内部对对象值的修改,提高安全性。
3.函数内部用if判断防止自身给自身赋值。
取地址运算符重载
取地址运算符重载分为两种:一种是普通类型的对象;一种是const修饰的常类型对象。
被const修饰的常类型对象只能调用同样具有const属性的函数或者成员,所有在第二种重载类型的末尾加const将默认的this指针修改为const this。此时不仅函数的返回值不能被修改,函数内部的成员也不能被修改。
小结:
1.const成员函数可以访问非const对象的非const数据成员、const数据 成员,也可以访问const对象内的所有数据成员,而不能修改它们。
2.非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不能访问const对象的任意数据成员。
3.在声明一个成员函数时,若该成员函数并不对数据成员进行修改操作,应尽可能将该成员函数声明为const成员。