一、const成员函数
const放在成员函数参数列表后面进行修饰,那么这个成员函数就是const成员函数;const实际修饰的是成员函数形参中包含的this指针的形参,表明在这个成员函数内部不能对成员进行修改。
例如日期类里面的Print成员函数,它的形参是Date* const this,用来接收实参&d,那么在这个Print函数参数列表后面加上const,Print函数隐含参数就成了 const Date* const this,那么就不能通过这个this指针来改变指向的对象的数据成员了。
const不能修饰默认成员函数,默认成员函数编译器可以自动生成,函数内部对对象的修改是根据类的不而来变化的,也就是说默认成员函数中对象的可修改性不能由const来决定。
###代码示例:
//const修饰成员函数
class Date
{
public:
Date()
{
_year = 1;
_month = 1;
_day = 1;
}
void Print( )const //实际参数是const Date* const this
{
cout << _year << " " << _month << " " << _day << endl;
}
bool operator==(const Date& d) const//实际参数是const Date* const this,const Date& d
{
return _year == d._year &&
_month == d._month &&
_day == d._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
d1.operator==(d2);//实参是&d1(参数类型是Date*)、d2;
d1.Print();//实参是&d1,参数类型是Date*
d2.Print();//实参是&d1,参数类型是Date*
const Date d3;
const Date d4;
d3.operator==(d4);//实参是&d3(参数类型是 const Date*)、d4
d3.Print();//实参是&d3,参数类型是(const Date*)
d4.Print();实参是&d4,参数类型是(const Date*)
return 0;
}
- d1、d2都是Date类型,重载运算符 (==) 函数传参是Date* 和Date,const成员函数(operator==) 的形参是 const Date* const this,const Date& d,实参相较形参是访问权限的缩小,不会有问题;同理成员函数 Print() 也是;
- d3、d4都是const Date类型,看到它们的Print() 函数,那么实参就是&d3或者&d4,对应的类型是const Date*,const成员函数恰好接收的就是const修饰指针指向的是对象内容的实参,那么这里就是访问权限的对等,自然不会有问题;
所以,给const成员函数传参时,传的可以是类的指针类型的实参,也可以是const修饰类的指针类型的实参;当然,const成员函数const是为了保证this指向的对象不被修改的,那么这个const修饰的成员函数定义时,自然不能出现要修改this指向的对象的行为。
###为理解透彻,再来看非const成员函数传参时访问权限放大的错误代码:
- d1类型是const Date,那么这个对象的成员是不能被修改的;此时调用Print()函数,传参实参是const Date*,但是形参是Date* const this,这个形参的意思是:this指针本身不能被修改,但是this指向的对象是可以被修改的,那么显然这时权限放大了,是错的;要解决,要么去掉const Date d1前的const,将d1类型改为Date;要么给Print()函数参数列表后面加上const,使其成为const成员函数。
二、取地址运算符重载
取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,一般来说,取地址运算符重载是不需要我们实现的,编译器自己生成的就可以满足我们的需求;
###代码示例:
class Date
{
public:
Date(int year=9,int month=1,int day=1)
{
_year = year;
_month = month;
_day = day;
}
//普通的取地址运算符重载
Date* operator&()
{
return this;
}
//const取地址运算符重载
//返回类型是const Date*,是因为const修饰了
const Date* operator&()const
{
return this;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
cout << &d1 << endl;
const Date d2;
cout << &d2 << endl;
}
仅靠编译器生成的默认取地址运算符重载也能取到类的地址: