C 语言面向对象风格封装的经典技巧(STM32F1 标准库实现)
“把函数装进结构体把结构体装进函数”是 C 语言中实现面向对象风格封装的经典技巧。它通过结构体容纳函数指针模拟“方法”再通过一个工厂函数返回该结构体的实例模拟“对象”从而将数据与操作绑定并隐藏具体实现。更换硬件时只需修改工厂函数内部的函数指针绑定调用方代码完全不变。一、核心思想函数装进结构体定义一个结构体其中包含多个函数指针成员这些指针指向与该模块相关的操作函数如init、on、off、toggle。这相当于定义了一个“接口”或“虚表”。结构体装进函数编写一个初始化/工厂函数在该函数内部定义该结构体类型的局部变量。将函数指针指向具体的硬件操作函数这些函数可以是static的对外不可见。返回该结构体或返回其指针调用方通过这个结构体来调用操作。效果调用方只看到结构体中的函数指针不知道底层是 GPIO、PWM 还是其他硬件。更换硬件时只需修改工厂函数内部的函数指针映射无需修改任何调用代码。二、示例可更换硬件的 LED 模块下面以 LED 控制为例展示如何将LED_On,LED_Off,LED_Toggle封装进结构体再通过一个函数返回该结构体。1. 定义接口结构体放在头文件中// led_interface.h#ifndef__LED_INTERFACE_H#define__LED_INTERFACE_Htypedefstruct{void(*init)(void);void(*on)(void);void(*off)(void);void(*toggle)(void);}LED_Ops;// 工厂函数返回封装了具体操作的 LED_Ops 结构体LED_OpsLED_Create(void);#endif2. 实现具体硬件操作隐藏在 .c 文件中// led_stm32.c (使用 STM32 标准库)#includeled_interface.h#includestm32f10x.h// 具体硬件配置更换硬件时只改这里#defineLED_PORTGPIOB#defineLED_PINGPIO_Pin_5#defineLED_PORT_CLKRCC_APB2Periph_GPIOB#defineLED_ON_LEVELBit_RESET// 低电平点亮#defineLED_OFF_LEVELBit_SET/* 前向声明所有静态函数 */staticvoidhw_init(void);staticvoidhw_on(void);staticvoidhw_off(void);staticvoidhw_toggle(void);// 内部实现函数static对外不可见staticvoidhw_init(void){GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(LED_PORT_CLK,ENABLE);GPIO_InitStructure.GPIO_PinLED_PIN;GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(LED_PORT,GPIO_InitStructure);hw_off();// 初始熄灭}staticvoidhw_on(void){GPIO_WriteBit(LED_PORT,LED_PIN,LED_ON_LEVEL);}staticvoidhw_off(void){GPIO_WriteBit(LED_PORT,LED_PIN,LED_OFF_LEVEL);}staticvoidhw_toggle(void){GPIO_WriteBit(LED_PORT,LED_PIN,(BitAction)(1-GPIO_ReadOutputDataBit(LED_PORT,LED_PIN)));}// 工厂函数实现将具体函数指针装入结构体并返回LED_OpsLED_Create(void){LED_Ops ops;ops.inithw_init;ops.onhw_on;ops.offhw_off;ops.togglehw_toggle;returnops;}3. 调用方代码完全与硬件无关// main.c#includeled_interface.hintmain(void){LED_Ops ledLED_Create();// 创建对象内部已绑定具体硬件操作led.init();// 初始化硬件while(1){led.on();delay(500000);led.off();delay(500000);// led.toggle();}}三、更换硬件时如何修改假设要将 LED 换到GPIOC, Pin 13且改为高电平点亮只需修改led_stm32.c中的宏定义和hw_on/hw_off的实现逻辑#defineLED_PORTGPIOC#defineLED_PINGPIO_Pin_13#defineLED_PORT_CLKRCC_APB2Periph_GPIOC#defineLED_ON_LEVELBit_SET// 高电平点亮#defineLED_OFF_LEVELBit_RESETstaticvoidhw_on(void){GPIO_WriteBit(LED_PORT,LED_PIN,LED_ON_LEVEL);}staticvoidhw_off(void){GPIO_WriteBit(LED_PORT,LED_PIN,LED_OFF_LEVEL);}// hw_toggle 会自动适应因为内部读取当前电平再翻转main.c和led_interface.h完全不需要改动。如果换成其他平台如 Arduino、Linux GPIO只需重写hw_xxx函数工厂函数内部的绑定随之改变上层代码依然不变。四、进阶使用指针返回结构体避免拷贝如果结构体较大可以返回指针// 头文件LED_Ops*LED_Create(void);// 实现文件staticLED_Ops ops;// 静态实例LED_Ops*LED_Create(void){ops.inithw_init;ops.onhw_on;ops.offhw_off;ops.togglehw_toggle;returnops;}// 调用LED_Ops*ledLED_Create();led-init();led-on();五、总结技巧作用示例函数装进结构体定义统一接口模拟类的成员函数LED_Ops包含on、off等函数指针结构体装进函数工厂模式封装具体实现隐藏硬件差异LED_Create()返回绑定好具体hw_xxx的结构体这种封装方式在嵌入式、驱动开发、库设计中非常常见如 Linux 内核的file_operations、RT-Thread 的设备驱动框架。它实现了接口与实现分离更换底层硬件时只需修改一个源文件真正做到了“更换硬件时仅需修改一处代码”。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2516188.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!