Menu
CoddyTech

在设置器中进行验证

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 20 课,共 61 课。

在上一课中,我们创建了只负责赋值的基本设置函数。但这样就错过了封装的一个重要好处:你可以添加验证逻辑来保护数据。

考虑一个永远不应变为负数的 Counter。如果没有封装,任何人都可以写入 c->value = -50,从而破坏状态。使用 setter,你可以控制哪些值是允许的:

// counter.c
void counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return;  // 直接忽略无效输入,不作提示
    }
    c->value = new_value;
}

现在,负值会被直接忽略。

你也可以选择返回状态码来表示成功或失败:

int counter_set_value(Counter *c, int new_value) {
    if (new_value < 0) {
        return 0;  // 失败
    }
    c->value = new_value;
    return 1;  // 成功
}

这种模式可以让调用方知道操作是否成功。关键在于,setter 不只是用于赋值,它们还是守门人,负责强制执行规则,限制对象的状态。封装真正的力量就在于:无论外部代码试图做什么,对象都能维护自身的完整性。

challenge icon

挑战

简单

我们来构建一个 Temperature 模块,通过在设置器中进行验证来保护数据。你将创建一个温度跟踪器,它只接受有效范围内的值:这将展示设置器如何充当对象状态的守门人。

你将创建 3 个文件:

  • temperature.h:使用不透明指针模式定义公共接口。仅通过前向声明声明 Temperature 类型。声明以下函数:
    • create_temperature:接收一个整数作为初始温度,并返回一个 Temperature 指针
    • free_temperature:释放已分配的内存
    • temp_get_degrees:获取当前温度值
    • temp_set_degrees:设置温度,返回一个 int(成功时为 1,失败时为 0)
    使用符号 TEMPERATURE_H 作为头文件保护宏。
  • temperature.c:定义实际的 struct Temperature,其中包含一个不可见的 int degrees 成员。实现所有函数。关键在于设置器:它只能接受 -50 到 150(含边界)的值。如果值超出此范围,则返回 0,并保持温度不变。如果值有效,则更新该值并返回 1。
  • main.c:尝试设置有效和无效的温度,以演示验证过程,并展示无效值会被拒绝,而有效值会被接受。

你将收到 3 个输入:初始温度、要设置的有效温度(在范围内),以及要尝试设置的无效温度(超出范围)。

在主文件中,使用初始值创建一个 Temperature 并打印它。然后尝试设置无效温度,由于它应该被拒绝,请打印结果并显示温度值保持不变。最后,设置有效温度,打印成功结果并显示更新后的值。释放内存并确认清理完成。

按以下格式打印输出:

Initial: {degrees}
Set {invalid}: {0 or 1}
After invalid: {degrees}
Set {valid}: {0 or 1}
After valid: {degrees}
Freed

例如,输入 25、100 和 200 时,输出如下:

Initial: 25
Set 200: 0
After invalid: 25
Set 100: 1
After valid: 100
Freed

这展示了封装的真正优势。无论外部代码尝试赋予什么值,你的设置器都会强制执行有效温度的规则,从而保护对象的完整性。

亲手试试

#include <stdio.h>
#include "temperature.h"

int main() {
    // 读取输入
    int initial, valid_temp, invalid_temp;
    scanf("%d", &initial);
    scanf("%d", &valid_temp);
    scanf("%d", &invalid_temp);
    
    // TODO:用初始值创建一个 Temperature 对象
    
    // TODO:输出初始温度
    // 格式:"Initial: {degrees}"
    
    // TODO:尝试设置无效温度
    // 输出结果,并显示值保持不变
    // 格式:"Set {invalid}: {0 or 1}"
    // 格式:"After invalid: {degrees}"
    
    // TODO:设置有效温度
    // 输出成功结果,并显示更新后的值
    // 格式:"Set {valid}: {0 or 1}"
    // 格式:"After valid: {degrees}"
    
    // TODO:释放内存并输出 "Freed"
    
    return 0;
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: C 在线编译器