这篇文章主要说类的6个默认成员函数:
构造函数、拷贝构造函数、析构函数、赋值操作符重载、取地址操作符重载、const修饰的取地址操作符重载
一、构造函数
1)定义:构造函数是一个特殊的成员函数,作用就是保证每个数据都有一个合适的初始值,初始化成员变量。
2)构造函数特性
1>函数名和类名相同,且没有返回值
2>新对象被创建时,由编译器自动调用,在对象的生命周期内置调用一次。
3>构造函数可以重载,实参类型决定调用哪个
4>无参的构造函数和带有缺省值的构造函数都认为是缺省的构造函数,并且缺省的构造函数只能有一个。
5>可以使用初始化列表
6>没有显示定义时,编译器自动合成一个默认的构造函数。
7>构造函数不能用const修饰
8>构造函数不能为虚函数
3)对象初始化
1>初始化列表 例:
class Date
{
public:
Date(int year,int month,int day)
:_year(year) //初始化列表
, _month(month)
, _day(day)
{
}
void printdate()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date b(2018, 6, 6);
b.printdate();
return 0;
}
2>注意: 1}每个成员在初始化列表中只能出现一次
2}初始化列表仅用于初始化类的成员变量,并不指定这些成员变量的初始化顺序,数据成员在类中定义顺序就是参数列表中的初始化顺序。
3}尽量避免使用成员初始化成员,成员的初始化顺序最好和成员定义的顺序保持一致。
3>一定要放在初始化列表中进行初始化:1}引用成员变量2}const成员变量3}类类型成员
class Date
{
public:
Date(int year,int month,int day)
: a(day)
, b(20)
{
}
private:
int& a;
const int b;
};
4>构造函数作用:
1}初始化/构造对象
2}类型转换
explict修饰构造函数,防止发生构造函数定义的隐式的类型转换,关键字写在类的声明上,定义时无需重复写出。
二、拷贝构造函数
1)定义:只有单个形参,而且该形参是本类类型对象的引用(常用const修饰),这样的构造函数称为拷贝构造函数。
2)拷贝构造函数是特殊的构造函数,创建对象时使用已经存在的类对象来初始化,编译器自动调用
3)例:
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)
{
}
void print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date b(2035, 8, 8);
Date d(b);
return 0;
}
4)特性:
1>拷贝构造函数是构造函数的重载,构造函数的性质拷贝构造函数也要满足。
2>参数必须使用类类型对象的引用传递-->防止递归引用,值传递时需要拷贝一份做形参,也会调用拷贝构造函数
3>如果没有显式定义,系统会自动合成一个默认的拷贝构造函数。默认的拷贝构造函数会依次拷贝类的数据成员完成初始化。
5)使用场景:对象实例化对象、作为函数参数、作为函数返回值。
三、析构函数
1)定义:与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成资源清理和释放内存等工作
2)特性:
1>在类名前加~,无参数无返回值。
2>一个类只能有一个析构函数。若未显式定义,系统自动合成缺省的析构函数
3>类对象生命周期结束时,编译系统自动调用析构函数
4>注意析构函数并不是删除对象,而是清理资源。对象的回收由编译器自动完成。
3)例:
class Array
{
public:
Array() //构造函数
:_array(NULL)
{
_array = new int[10];
}
~Array() //析构函数
{
delete[] _array;
}
private:
int * _array;
};
四、赋值运算符重载
1)定义:重载操作符是具有特殊函数名的函数,关键字operator后面接需要定义的操作符符号。操作符重载本身也是一个函数,具有返回值和形参表。它的形参数目与操作符的操作数目相同,使用运算符重载可以提高代码的可读性。
2)注意:
1>不能通过连接其他符号来创建新的操作符
2>重载操作符必须有一个类类型或者枚举类型的操作数。
3>用于内置类型的操作符,其含义不能改变,以前是什么样的算法重载后还应是什么样的
4>作为类成员的重载函数,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this
5>一般将算数操作符定义为非成员函数,将赋值运算符定义为成员函数
6>操作符定义为非类的成员函数时,一般将其定义为类的友元
7>==和!=要成对重载
8>[] :一个非const成员并返回引用,一个是const成员并返回引用
9>解引用*和->,不显示任何参数
10>前置++/--必须返回新值的引用,后缀必须返回旧值,应该是值返回而不是引用返回
11>输入>>和输出<<必须定义为类的友元函数
日期类就是对运算符重载的多次引用
五、取地址操作符重载
class Test
{
public:
Test * operator&()
{
return this;
}
const Test * operator&() const //第二个const修饰this指针
{
return this;
}
private:
};
int main()
{
Test t1;
cout << &t1 << endl;
const Test t2;
cout << &t2 << endl;
return 0;
}