前言:
一个类的成员函数:会有隐含的 this 指针作为函数第一个参数,这个成员函数没有被 const 修饰时,this 指针的类型为 Date* const(const 修饰 this,this 不能被修改)
正文:由例子引入
例一:
有时候,定义对象可能会加一个 const 修饰:使 *this 不能被修改
void TestDate()
{
const Date d1(2024, 4, 4);
}
此时 调用该对象的成员函数 Print:会出现报错,为什么??(自己编译一下可知)
void Date::Print();
{
cout << _year << "/" << _month << "/" << _day << '\n';
}
void TestDate()
{
const Date d1(2024, 4, 4);
d1.Print(); // 调用该对象的成员函数 Print
}
这里的报错:涉及 const 权限放大的问题
d1.Print(); 是传递 &d1 ,类型为 const Date* :这个意思是,对象d1 的指针指向的内容不能被修改
而 Print函数参数为 Date* this
显然,权限被放大了
如何解决?把 函数的 this 也改成 const Date* (两两匹配上),但是由于 this指针 是隐含的,无法直接使用 const修饰,那 Print函数应该怎么调整?
解决办法:用 const 修饰成员函数
做法:因为没办法直接显式的修饰 *this ,则定性规定在成员函数 右边加上,表示修饰 * this,本质是改变 this 的类型(const Date* this :const 修饰 * this) 同时,原来的 this 本身是 Date* const this : this指针是不能修改的 现在又加一个const 修饰,则变成:const Date* const this
修改后的函数变成:
void Date::Print() const;
再定义一个,非 const 修饰的对象,可见:非 const 可以调用 const修饰 的Print:即 权限可以缩小
void TestDate()
{
// 再定义一个,非 const 可以调用 const 的Print:权限可以缩小
Date d2(2024, 4, 4);
d2.Print();
}
小结:函数添加了 const,有 const修饰的对象 和 无const 修饰的对象 都能调用,因此函数能写 const 就写,安全性增加(保护对象本身)
例二:
使用日期类中的 运算符重载函数 举个例子:这里仅仅讨论关于 const 的部分
// 运算符重载函数:无需理会内部的实现,关注 函数声明部分即可
bool Date::operator<(const Date& d)
{
// .....
}
void TestDate()
{
const Date d1(2024, 4, 4);
Date d2(2024, 4, 4);
// 为什么下面第一条式子会报错,第二条式子补会报错?
d1 < d2; // d1 是 *this, d2 是用函数参数 const Date& d 接收
d2 < d1; // d2 是 *this, d1 是用函数参数 const Date& d 接收
}
运算符重载函数的第一个参数: this 指针为 Date const* 类型,第二个参数:const Date
第一条式子(d1 < d2;),d1 是 const修饰的,但是重载函数的 this 指针没有 const修饰,因此和上一个例子同理,权限放大了
修改调整:函数加上 const,使 this指针被 const 修饰
bool Date::operator<(const Date& d) const
{
// .....
}
总结:
如果对象本身不涉及修改对象(如 拷贝构造、赋值重载….等函数需要修改 对象,就不能加const了),则 函数都需要用 const 修饰(都加上)
思考题:
1、const对象可以调用非const成员函数吗?不可以,权限放大:const Date* 调用 Date*
2、非const对象可以调用const成员函数吗?可以,权限缩小:Date* 调用 const Date*
3、const成员函数内可以调用其它的非const成员函数吗?
不可以,权限放大:const Date* 调用 Date*
4、非const成员函数内可以调用其它的const成员函数吗?
可以,权限缩小:Date* 调用 const Date*
这几个问题都是围绕【const 的权限可以缩小和平移,就是不能放大】的核心解决问题
【问题】const 的对象(或函数)可以调用 const函数,那如何调用 非const的函数?
强制类型转换:const_cast<T&>(对象名).成员函数; (T为类型 名)
举例:
class A {
public:
A() { };
void Print() const {
cout << "Print" << '\n';
}
private:
int _a;
};
int main()
{
const A a; // a 使对象名,A 是类型名
const_cast<A&>(a).Print();
return 0;
}