Menu
CoddyTech

多态迭代

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

你已经学会了创建接口,并用不同的具体函数实现它们。真正的价值在于,你可以统一处理一组不同的对象:遍历它们,并对每个对象调用同一个函数指针,而不必考虑其中具体关联的是哪种行为。

想象一下,你有一个由 Action 结构体组成的数组,每个结构体都分配了自己的 execute 函数:

typedef void (*ExecuteFunc)(void);

typedef struct {
    const char* name;
    ExecuteFunc execute;
} Action;

void jump(void) { printf("Jumping!\n"); }
void run(void)  { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }

你可以创建一个由这些操作组成的数组,并为每个操作关联不同的函数,然后用一个简单的 for 循环遍历它们:

int main() {
    Action actions[3] = {
        { "Jump", jump },
        { "Run", run },
        { "Rest", rest }
    };
    
    for (int i = 0; i < 3; i++) {
        printf("%s: ", actions[i].name);
        actions[i].execute();
    }
    return 0;
}

循环并不知道也不关心每个操作在内部具体做什么。它只会对每个元素调用 execute()。

这就是多态的作用:同一段代码可以处理行为完全不同的对象。添加新的操作类型无需更改迭代逻辑,只需向数组中添加另一个元素。

challenge icon

挑战

简单

让我们构建一个 Task 管理系统,演示多态迭代:处理一组共享相同接口、但执行不同操作的对象。

你需要将代码放在三个文件中:

  • task.h:在这里定义任务接口。创建一个名为 TaskFunc 的函数指针类型,它不接受任何参数,也不返回任何值。然后定义一个 Task 结构体,其中包含一个 name(类型为 const char*)和一个类型为 TaskFunc 的 run 函数指针。
  • task.c:实现三个不同的任务函数,分别代表不同类型的工作:
    • backup_task:打印 Backing up data...
    • cleanup_task:打印 Cleaning up files...
    • report_task:打印 Generating report...
  • main.c:在这里整合所有内容。创建一个由 Task 结构体组成的数组,并为每个结构体指定不同的任务函数。然后遍历数组并以多态方式执行每个任务:对于每个任务,打印它的名称,再调用它的 run 函数。

程序会接收一个输入:要运行的任务数量(1、2 或 3)。

创建一个恰好包含三个任务的数组,顺序如下:名为 Backup 的备份任务、名为 Cleanup 的清理任务,以及名为 Report 的报告任务。根据输入的数量,只从数组开头开始遍历相应数量的任务。

遍历每个任务时,先打印任务名称,再打印冒号和空格,然后调用它的 run 函数。

输入为 2 时的输出示例:

Backup: Backing up data...
Cleanup: Cleaning up files...

输入为 3 时的输出示例:

Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...

关键在于,循环不需要知道每个任务具体要做什么。它只需打印名称,并对每个元素调用 run()。同一段迭代代码可以统一处理所有任务类型。记得在头文件中使用包含保护。

亲手试试

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

// 声明在 task.c 中实现的任务函数
void backup_task(void);
void cleanup_task(void);
void report_task(void);

int main() {
    int count;
    scanf("%d", &count);
    
    // TODO: 按以下顺序创建一个包含 3 个 Task 结构体的数组:
    // 1. 名为 "Backup" 的备份任务,使用 backup_task
    // 2. 名为 "Cleanup" 的清理任务,使用 cleanup_task
    // 3. 名为 "Report" 的报告任务,使用 report_task
    
    // TODO: 遍历数组中的 'count' 个任务
    // 对每个任务,先打印 "<name>: ",再调用它的 run 函数
    
    return 0;
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: C 在线编译器