Menu
CoddyTech

接口概念

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

到目前为止,我们的结构体都把数据和行为混在一起了,比如名称和函数指针放在一起。但如果结构体只包含函数指针呢?这样就能创建出一种强大的东西:接口。

接口定义了有哪些操作可用,但不指定它们如何工作。它是一份契约,说明“任何实现此接口的对象都必须提供这些函数。”

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

ILogger 结构体只包含一个函数指针。它本身没有任何数据,只描述行为。“I” 前缀是一种常见约定,表示这是一个接口。

任何接受 ILogger 的代码都不关心日志消息会发送到哪里。它可以输出到控制台、写入文件,或通过网络发送数据。调用方只知道可以调用 log:

void process(ILogger* logger, const char* msg) {
    logger->log(msg);  // 我们不知道它具体是怎么记录日志的。
}

这种分离是多态的本质。process 函数可以与任何日志记录器实现配合使用。你可以切换行为,而无需更改函数的代码。在下一课中,你将创建符合此接口契约的具体实现。

challenge icon

挑战

简单

让我们来构建一个 ICalculator 接口:这是一个只包含函数指针的结构体,用来定义任何计算器都必须支持哪些操作,而不指定这些操作如何实现。

你需要创建两个文件来组织代码:

  • calculator.h:在这里定义接口。创建一个名为 BinaryOp 的函数指针类型,它接受两个 int 参数并返回一个 int。然后定义一个 ICalculator 结构体,其中只包含两个函数指针:operate(类型为 BinaryOp)和 describe(一个不接受参数且不返回值的函数指针)。这个结构体纯粹是一个接口,不包含数据,只定义行为。
  • main.c:包含头文件,并实现能够满足该接口的具体函数:
    • add:返回两个整数的和
    • multiply:返回两个整数的乘积
    • describe_add:输出 Addition
    • describe_multiply:输出 Multiplication
    然后创建一个 ICalculator 实例,根据输入为它连接相应的函数,并使用它执行计算。

程序会接收 3 个输入:两个整数和一个操作代码(1 表示加法,2 表示乘法)。

根据操作代码,为 ICalculator 连接相应的一对函数。然后通过接口调用 describe 输出操作名称,接着调用 operate 进行计算并输出结果。

输入为 5、3 和 1 时的示例输出:

Addition
8

输入为 4、7 和 2 时的示例输出:

Multiplication
28

关键在于,ICalculator 结构体定义了一份契约:使用它的代码可以调用 describe 和 operate,而不需要知道具体连接的是哪些函数。记得在头文件中使用包含保护。

亲手试试

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

// TODO:实现 add 函数
// 返回两个整数的和


// TODO:实现 multiply 函数
// 返回两个整数的乘积


// TODO:实现 describe_add 函数
// 打印 "Addition"


// TODO:实现 describe_multiply 函数
// 打印 "Multiplication"


int main() {
    int num1, num2, op_code;
    scanf("%d", &num1);
    scanf("%d", &num2);
    scanf("%d", &op_code);
    
    // TODO:创建一个 ICalculator 实例
    
    
    // TODO:根据 op_code(1 表示 add,2 表示 multiply),
    // 为计算器配置相应的函数
    
    
    // TODO:通过接口调用 describe
    
    
    // TODO: 通过接口调用 operate,并打印结果
    
    
    return 0;
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: C 在线编译器