在设置器中进行验证
本课属于 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 不只是用于赋值,它们还是守门人,负责强制执行规则,限制对象的状态。封装真正的力量就在于:无论外部代码试图做什么,对象都能维护自身的完整性。
挑战
简单我们来构建一个 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;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C 在线编译器