Menu
CoddyTech

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。

challenge icon

挑战

简单

我们来编写一个温度转换器,看看何时以及为什么要使用 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;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C++ 在线编译器