当前位置: 首页 > news >正文

C语言模拟面向对象编程方法之封装

目录

    • C++ 中抽象封装
      • 封装的介绍:
      • 封装的用途:
      • 封装使用实例
    • C语言模拟面向对象抽象封装
      • 模拟过程
      • 实际使用
    • 嵌入式开发中实际案例介绍
      • 1. STM32 HAL库(芯片固件库)
      • 2. FreeRTOS(开源RTOS)
      • 3. LVGL(开源GUI库)
      • 4. Contiki-NG(开源物联网OS)
      • 5. Zephyr RTOS驱动模型
      • 6. 嵌入式中间件 - Paho MQTT
    • 总结
      • 差异原因
      • 模拟特点

C++ 中抽象封装

封装的介绍:

封装是面向对象编程的三大特性之一,它将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

封装的意义:

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

封装优点:

  • 将所有成员属性设置为私有,可以自己控制读写权限
  • 对于写权限,我们可以检测数据的有效性

封装的用途:

  • 保护数据完整性:通过私有成员变量和公共接口控制数据访问
  • 隐藏实现细节:外部只能通过公共接口与对象交互,内部实现可以随时修改
  • 提高代码可维护性:修改内部实现不会影响外部代码
  • 实现数据验证:在setter方法中添加数据验证逻辑

封装使用实例

class BankAccount {
private:std::string accountNumber;double balance;std::string ownerName;// 私有方法,外部不能调用bool isValidAmount(double amount) {return amount > 0;}public:BankAccount(const std::string& accNum, const std::string& owner, double initBalance) : accountNumber(accNum), ownerName(owner), balance(initBalance) {}// 公共接口 - 获取信息std::string getAccountNumber() const { return accountNumber; }std::string getOwnerName() const { return ownerName; }double getBalance() const { return balance; }// 公共接口 - 操作bool deposit(double amount) {if (isValidAmount(amount)) {balance += amount;return true;}return false;}bool withdraw(double amount) {if (isValidAmount(amount) && balance >= amount) {balance -= amount;return true;}return false;}void displayInfo() const {std::cout << "Account: " << accountNumber << ", Owner: " << ownerName << ", Balance: $" << balance << std::endl;}
};// 使用
BankAccount account("123456", "Alice", 1000.0);
account.deposit(500.0);    // 正确操作
account.withdraw(200.0);   // 正确操作
// account.balance = 1000000.0;  // 错误!balance是私有的

C语言模拟面向对象抽象封装

C语言本身没有类的概念,但可以通过结构体和函数指针来模拟封装。关键是通过头文件暴露公共接口,隐藏实现细节,在源文件中实现具体功能

模拟过程

// bank_account.h - 头文件只暴露公共接口
#ifndef BANK_ACCOUNT_H
#define BANK_ACCOUNT_H// 前向声明,隐藏内部结构
typedef struct BankAccount_Private BankAccount;// 创建和销毁函数
BankAccount* bank_account_create(const char* account_number, const char* owner_name, double initial_balance);
void bank_account_destroy(BankAccount* account);// 公共接口函数
const char* bank_account_get_number(const BankAccount* account);
const char* bank_account_get_owner(const BankAccount* account);
double bank_account_get_balance(const BankAccount* account);int bank_account_deposit(BankAccount* account, double amount);
int bank_account_withdraw(BankAccount* account, double amount);
void bank_account_display_info(const BankAccount* account);#endif // BANK_ACCOUNT_H
// bank_account.c - 源文件实现内部细节
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "bank_account.h"// 私有结构体定义,外部不可见
struct BankAccount_Private {char account_number[20];char owner_name[50];double balance;// 私有方法指针(可选)int (*is_valid_amount)(double amount);
};// 私有方法实现
static int is_valid_amount(double amount) {return amount > 0;
}// 创建对象
BankAccount* bank_account_create(const char* account_number, const char* owner_name, double initial_balance) {// 参数验证if (!account_number || !owner_name || initial_balance < 0) {return NULL;}BankAccount* account = (BankAccount*)malloc(sizeof(BankAccount));if (!account) {return NULL;}// 初始化成员strncpy(account->account_number, account_number, sizeof(account->account_number) - 1);account->account_number[sizeof(account->account_number) - 1] = '\0';strncpy(account->owner_name, owner_name, sizeof(account->owner_name) - 1);account->owner_name[sizeof(account->owner_name) - 1] = '\0';account->balance = initial_balance;account->is_valid_amount = is_valid_amount;return account;
}// 销毁对象
void bank_account_destroy(BankAccount* account) {if (account) {free(account);}
}// 公共接口实现
const char* bank_account_get_number(const BankAccount* account) {return account ? account->account_number : NULL;
}const char* bank_account_get_owner(const BankAccount* account) {return account ? account->owner_name : NULL;
}double bank_account_get_balance(const BankAccount* account) {return account ? account->balance : 0.0;
}int bank_account_deposit(BankAccount* account, double amount) {if (!account || !account->is_valid_amount(amount)) {return 0;}account->balance += amount;return 1;
}int bank_account_withdraw(BankAccount* account, double amount) {if (!account || !account->is_valid_amount(amount) || account->balance < amount) {return 0;}account->balance -= amount;return 1;
}void bank_account_display_info(const BankAccount* account) {if (account) {printf("Account: %s, Owner: %s, Balance: $%.2f\n",account->account_number, account->owner_name, account->balance);}
}

实际使用

// main.c - 使用封装的银行账户
#include <stdio.h>
#include "bank_account.h"int main() {// 创建账户对象BankAccount* account = bank_account_create("123456", "Alice", 1000.0);if (!account) {printf("Failed to create account!\n");return -1;}// 使用公共接口操作对象bank_account_display_info(account);// 存款和取款if (bank_account_deposit(account, 500.0)) {printf("Deposit successful!\n");} else {printf("Deposit failed!\n");}if (bank_account_withdraw(account, 200.0)) {printf("Withdrawal successful!\n");} else {printf("Withdrawal failed!\n");}// 尝试非法操作会被拒绝if (!bank_account_withdraw(account, -100.0)) {printf("Invalid withdrawal amount rejected!\n");}if (!bank_account_withdraw(account, 2000.0)) {printf("Insufficient balance withdrawal rejected!\n");}bank_account_display_info(account);// 获取信息printf("Account owner: %s\n", bank_account_get_owner(account));printf("Current balance: $%.2f\n", bank_account_get_balance(account));// 清理bank_account_destroy(account);return 0;
}

嵌入式开发中实际案例介绍

1. STM32 HAL库(芯片固件库)

// stm32f4xx_hal_gpio.h - 公共接口
typedef struct {uint32_t Pin;       /*!< 指定要配置的GPIO引脚 */uint32_t Mode;      /*!< 指定GPIO引脚的操作模式 */uint32_t Pull;      /*!< 指定GPIO引脚的上拉/下拉 */uint32_t Speed;     /*!< 指定GPIO引脚的速度 */uint32_t Alternate; /*!< 指定GPIO引脚的复用功能 */
} GPIO_InitTypeDef;// 公共函数
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);// 使用示例 - 用户只关心接口,不关心内部实现
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);

2. FreeRTOS(开源RTOS)

// task.h - 任务管理公共接口
typedef void * TaskHandle_t;// 创建任务函数 - 隐藏内部任务控制块细节
BaseType_t xTaskCreate(TaskFunction_t pvTaskCode,const char * const pcName,configSTACK_DEPTH_TYPE usStackDepth,void * pvParameters,UBaseType_t uxPriority,TaskHandle_t * pvCreatedTask);// 任务管理函数
void vTaskDelete(TaskHandle_t xTaskToDelete);
void vTaskDelay(const TickType_t xTicksToDelay);
UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask);// 使用示例 - 用户不关心任务控制块内部结构
TaskHandle_t xTaskHandle;
xTaskCreate(vTaskFunction, "MyTask", 1000, NULL, 1, &xTaskHandle);
vTaskDelay(1000 / portTICK_PERIOD_MS);

3. LVGL(开源GUI库)

// lv_obj.h - 对象系统公共接口
typedef struct _lv_obj_t lv_obj_t;// 创建和删除函数
lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy);
void lv_obj_del(lv_obj_t * obj);// 设置属性函数 - 隐藏内部属性存储细节
void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h);
void lv_obj_set_pos(lv_obj_t * obj, lv_coord_t x, lv_coord_t y);
void lv_obj_set_style(lv_obj_t * obj, lv_style_t * style);// 获取属性函数
lv_coord_t lv_obj_get_width(const lv_obj_t * obj);
lv_coord_t lv_obj_get_height(const lv_obj_t * obj);// 使用示例
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_size(btn, 100, 50);
lv_obj_set_pos(btn, 10, 10);

4. Contiki-NG(开源物联网OS)

// sensor.h - 传感器抽象接口
struct sensors_sensor;// 传感器驱动结构体 - 定义标准接口
struct sensors_sensor {char *name;int (* value)(int type);int (* configure)(int type, int value);int (* status)(int type);
};// 传感器访问函数
int sensors_sensor_get_value(const struct sensors_sensor *s, int type);
int sensors_sensor_configure(struct sensors_sensor *s, int type, int value);// 具体传感器实现被封装在.c文件中
extern struct sensors_sensor tmp102_sensor;
extern struct sensors_sensor sht11_sensor;// 使用示例 - 统一接口访问不同传感器
int temp = sensors_sensor_get_value(&tmp102_sensor, SENSOR_TYPE_TEMPERATURE);
int humidity = sensors_sensor_get_value(&sht11_sensor, SENSOR_TYPE_HUMIDITY);

5. Zephyr RTOS驱动模型

// device.h - 设备驱动抽象层
typedef void (*device_pm_control_callback)(const struct device *dev,int command,void *context);// 设备结构体 - 对应用层隐藏具体实现
struct device {const char *name;const void *config;void * const data;const struct device_config *device_config;device_pm_control_callback device_control;
};// 设备操作接口
const struct device *device_get_binding(const char *name);
int device_set_power_state(const struct device *dev, uint32_t state);// 驱动特定的操作通过API结构体封装
struct uart_driver_api {int (*poll_in)(const struct device *dev, unsigned char *pChar);void (*poll_out)(const struct device *dev, unsigned char outChar);
};// 使用示例
const struct device *uart_dev = device_get_binding("UART_0");
const struct uart_driver_api *api = (const struct uart_driver_api *)uart_dev->api;
api->poll_out(uart_dev, 'A');

6. 嵌入式中间件 - Paho MQTT

// MQTTClient.h - MQTT客户端公共接口
typedef void* MQTTClient;// 创建和销毁客户端
int MQTTClient_create(MQTTClient* handle, const char* serverURI, const char* clientId, int persistence_type, void* persistence_context);
void MQTTClient_destroy(MQTTClient* handle);// 连接管理
int MQTTClient_connect(MQTTClient handle, MQTTClient_connectOptions* options);
int MQTTClient_disconnect(MQTTClient handle, int timeout);// 消息发布和订阅
int MQTTClient_publish(MQTTClient handle, const char* topicName, int payloadlen, void* payload, int qos, int retained);
int MQTTClient_subscribe(MQTTClient handle, const char* topic, int qos);// 使用示例 - 隐藏网络通信细节
MQTTClient client;
MQTTClient_create(&client, "tcp://localhost:1883", "client1", MQTTCLIENT_PERSISTENCE_NONE, NULL);MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
conn_opts.keepAliveInterval = 20;
conn_opts.cleansession = 1;MQTTClient_connect(client, &conn_opts);
MQTTClient_publish(client, "test/topic", strlen("Hello"), "Hello", 1, 0);

总结

差异原因

  1. C++原生封装:通过private、protected、public关键字天然支持,编译器强制访问控制

  2. C语言模拟:通过头文件分离接口和实现,在源文件中隐藏私有数据和函数

  3. 访问控制:C语言没有语言级别的访问控制,需要通过编程规范和组织代码来实现

模拟特点

  1. 头文件作为接口:只声明公共函数和抽象类型

  2. 源文件隐藏实现:在.c文件中定义具体结构和私有函数

  3. 不透明指针:使用前向声明隐藏内部数据结构

  4. 命名规范:通过命名约定区分公共接口和私有实现

  5. 编译时封装:通过静态链接隐藏实现,用户只能看到头文件声明的接口

这种封装方式在嵌入式系统中广泛应用,既保持了C语言的高效性,又获得了面向对象的封装好处,是嵌入式领域重要的设计模式。

http://www.dtcms.com/a/454393.html

相关文章:

  • 公司制作网站价格表莱芜生活网
  • 购物网站asp源码门户网站维护
  • 0.5 数据增强、keras模型保存以及读取、绘制loss过程
  • wordpress网站维护页面模板做网站材料
  • 8.复合查询与内外连接
  • load_dotenv() 加载环境变量
  • 【C语言基础】数据类型、运算符与控制语句详解
  • 无限容量网站灵山建设局网站
  • 站长工具网站怎么做外围网站代理
  • 安泽网站建设网站seo在线检测
  • 廊坊企业建站模板东莞哪家做网站好
  • 做网站空间多大做网站前需要做什么准备
  • 中国建设工程造价管理协会登录网站wap网站排名
  • 商业网站建设设计装饰中国建设银行网站下载
  • 鸿蒙跨端开发:ArkTS与Java混合编程的性能边界测试
  • c 可以做网站嘛深度网络
  • StrFormatByteSize 函数:从字节到可读大小的转换
  • 服务器 做网站网站基础代码html
  • 【LaTeX】 15 LaTeX 错误处理指南
  • 建设新网站征求意见电商网站建设求职定位
  • 怎样拍照产品做网站安徽合肥中国建设银行网站首页
  • JSP 表达式语言
  • DeepSeek“问道”-第九章:问救赎 —— 携镣铐而舞,向宽阔处行
  • 网站开发需要学些什么网站建设与管理的网页
  • 好听的网站名称建一个网站首先要怎么做
  • 2025-10-07 考场防烫tips P5091
  • 零件加工网微软优化大师
  • 第五十章 ESP32S3 WiFi 热点实验
  • 在线个人资料制作网站一键生成微信小程序平台
  • sed 命令使用手册