const 成员函数
本课属于 Coddy C++ 学习旅程的“面向对象编程”单元。第 29 课,共 104 课。
你在上一课中已经见过 getter 方法上的 const 关键字。但当 const 出现在函数的参数列表之后时,它具体是什么意思?const 成员函数承诺不会修改对象的任何成员变量。
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int getArea() const { // const 成员函数
return width * height; // 可以读取成员变量
}
void setWidth(int w) { // 非 const:会修改对象
width = w;
}
};参数列表后的 const 告诉编译器:“这个函数不会改变对象的状态。”如果你尝试在 const 函数中修改成员变量,编译器会报错。
处理 const 对象或 const 引用时,这一点至关重要。const 对象只能调用 const 成员函数:
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // 正确:getArea() 是 const
// rect.setWidth(10); // 错误:setWidth() 不是 const
}如果函数不会修改对象,把它们标记为 const 是一种良好的做法。这样可以说明你的意图,让函数能够处理 const 对象,还能帮助编译器发现意外的修改。只读取数据的成员函数都应该标记为 const。
挑战
简单我们来编写一个温度转换器,看看何时以及为什么要使用 const 成员函数。你将创建一个类,其中一些方法只读取数据(应该标记为 const),另一些方法则会修改对象的状态。
你将创建两个文件来组织代码:
Temperature.h:定义一个Temperature类,用于存储温度值,并提供多种读取和修改温度的方式。你的类应包含:- 一个私有成员
celsius(double),用于存储温度 - 一个接收初始摄氏温度值的构造函数
- 一个返回已存储值的
getCelsius()方法。由于它只读取数据,因此应该标记为 const - 一个使用公式
celsius * 9.0 / 5.0 + 32.0计算并返回华氏温度的getFahrenheit()方法。由于它不会修改任何内容,也应该标记为 const - 一个使用
celsius + 273.15返回开尔文温度的getKelvin()方法,它也应该标记为 const - 一个用于更新已存储温度的
setCelsius(double value)方法。由于它会修改对象,因此不能标记为 const - 一个将增量加到当前温度上的
adjustBy(double delta)方法,它也不能标记为 const
- 一个私有成员
main.cpp:演示 const 成员函数如何与普通对象和 const 对象配合使用。从输入中读取一个初始温度值,然后:- 使用输入值创建一个
Temperature对象 - 打印
"Initial: <celsius>C = <fahrenheit>F = <kelvin>K" - 将温度增加
10.0度 - 打印
"After adjustment: <celsius>C" - 创建一个辅助函数
void printReadings(const Temperature& temp),让它接收一个 const 引用并打印"Reading: <celsius>C, <fahrenheit>F"。此函数只能调用 temp 上标记为 const 的方法 - 使用你的温度对象调用
printReadings() - 将温度设为
0.0(冰点) - 打印
"Freezing point: <celsius>C = <fahrenheit>F"
- 使用输入值创建一个
使用 <iomanip> 中的 std::fixed 和 std::setprecision(1),将所有温度值格式化为保留一位小数。
这里的关键在于,printReadings() 接收的是一个 const 引用,因此它只能调用标记为 const 的方法。这就是为什么要正确地将 getter 方法标记为 const。这样,这些方法就能在对象无法被修改的情境中使用。
亲手试试
#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;
// TODO: 在这里实现 Temperature 类的方法
// 构造函数
Temperature::Temperature(double initialCelsius) {
// TODO: 初始化 celsius
}
// TODO: 将 getCelsius() 实现为 const 方法
// TODO: 将 getFahrenheit() 实现为 const 方法
// TODO: 将 getKelvin() 实现为 const 方法
// TODO: 实现 setCelsius(double value)
// TODO: 实现 adjustBy(double delta)
// TODO: 创建辅助函数 printReadings,接收一个 const Temperature& 参数
// 并打印 "Reading: <celsius>C, <fahrenheit>F"
// 注意:这个函数只能调用 temp 的 const 方法!
int main() {
double initialTemp;
cin >> initialTemp;
// 设置输出格式
cout << fixed << setprecision(1);
// TODO: 用输入值创建一个 Temperature 对象
// TODO: 输出 "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
// TODO: 将温度调整 10.0 度
// TODO: 输出 "After adjustment: <celsius>C"
// TODO: 用你的温度对象调用 printReadings()
// TODO: 将温度设为 0.0(冰点)
// TODO: 输出 "Freezing point: <celsius>C = <fahrenheit>F"
return 0;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C++ 在线编译器