C语言模拟面向对象编程方法之this指针
目录
- C++ 中this指针的作用
- this指针的介绍:
- this指针的用途:
- this指针使用实例
- C语言模拟面向对象this指针
- 模拟过程
- 实际使用
- 嵌入式开发中实际案例介绍
- 1. STM32 HAL库(芯片固件库)
- 2. FreeRTOS(开源RTOS)
- 3. LVGL(开源GUI库)
- 4. Contiki-NG(开源物联网OS)
- 5. Zephyr RTOS驱动模型
- 6. 嵌入式中间件 - Paho MQTT
- 总结
- 差异原因
- 模拟特点
C++ 中this指针的作用
this指针的介绍:
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分那个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可
this指针的用途:
- 当形参和成员变量同名时,可用this指针来区分
- 在类的非静态成员函数中返回对象本身,可使用return *this
this指针使用实例
class Person {
private:std::string name;int age;public:Person(const std::string& n, int a) : name(n), age(a) {}void introduce() {// this指针隐式可用,指向当前对象std::cout << "Hello, I'm " << this->name << ", " << this->age << " years old." << std::endl;}void birthday() {this->age++; // 可以直接访问成员std::cout << this->name << " is now " << this->age << " years old!" << std::endl;}
};// 使用
Person person("Alice", 25);
person.introduce(); // 自动传递this指针
C语言模拟面向对象this指针
由于C++的方法是嵌套在类结构体里面的,所以说,this指针直接就可以表示是指向当前类型的结构体,当我们使用C语言模拟这个面向对象的思想时,由于结构体中只能嵌套函数指针,函数指针指向的函数并非知道当前它属于的结构体是什么?所以说我们需要将当前操作的结构体指针以参数传入函数也就是方法中模拟this指针的效果
模拟过程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定义"类"结构体
typedef struct {char name[50];int age;// 函数指针作为"方法"void (*introduce)(void* self);void (*birthday)(void* self);void (*set_age)(void* self, int new_age);
} Person;// "方法"的实现
void person_introduce(void* self) {Person* this = (Person*)self; // 显式转换,模拟this指针printf("Hello, I'm %s, %d years old.\n", this->name, this->age);
}void person_birthday(void* self) {Person* this = (Person*)self;this->age++;printf("%s is now %d years old!\n", this->name, this->age);
}void person_set_age(void* self, int new_age) {Person* this = (Person*)self;this->age = new_age;
}// "构造函数"
Person* person_create(const char* name, int age) {Person* person = (Person*)malloc(sizeof(Person));strcpy(person->name, name);person->age = age;// 绑定方法person->introduce = person_introduce;person->birthday = person_birthday;person->set_age = person_set_age;return person;
}// "析构函数"
void person_destroy(Person* person) {free(person);
}
实际使用
int main() {// 创建对象Person* alice = person_create("Alice", 25);Person* bob = person_create("Bob", 30);// 调用方法 - 必须显式传递对象指针作为thisalice->introduce(alice); // 输出: Hello, I'm Alice, 25 years old.bob->introduce(bob); // 输出: Hello, I'm Bob, 30 years old.alice->birthday(alice); // 输出: Alice is now 26 years old!alice->set_age(alice, 27);alice->introduce(alice); // 输出: Hello, I'm Alice, 27 years old.// 清理person_destroy(alice);person_destroy(bob);return 0;
}
嵌入式开发中实际案例介绍
1. STM32 HAL库(芯片固件库)
// 在 stm32f4xx_hal_uart.h 中
typedef struct __UART_HandleTypeDef
{USART_TypeDef *Instance; /*!< UART registers base address */UART_InitTypeDef Init; /*!< UART communication parameters */uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */uint16_t TxXferSize; /*!< UART Tx Transfer size */// ... 其他成员// 方法(函数指针)HAL_StatusTypeDef (*Transmit)(struct __UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);HAL_StatusTypeDef (*Receive)(struct __UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
} UART_HandleTypeDef;// 在 stm32f4xx_hal_uart.c 中的实现
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{// huart 就是 this 指针if(huart->gState == HAL_UART_STATE_READY){huart->pTxBuffPtr = pData;huart->TxXferSize = Size;// ... 具体实现}return HAL_OK;
}// 使用示例
UART_HandleTypeDef huart1;
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
// ...
HAL_UART_Transmit(&huart1, data, sizeof(data), 1000); // 显式传递this指针
2. FreeRTOS(开源RTOS)
// 队列对象
typedef struct QueueDefinition
{int8_t *pcHead; /*< 队列存储区开始位置 */int8_t *pcTail; /*< 队列存储区结束位置 */// ... 其他数据成员// 方法(通过函数实现,第一个参数总是队列句柄)
} xQUEUE;// 队列操作函数 - 第一个参数就是this指针
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait )
{Queue_t * const pxQueue = ( Queue_t * ) xQueue; // 转换为具体类型// 访问对象成员if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ){// ... 实现发送逻辑}return pdTRUE;
}// 使用
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
xQueueSend(xQueue, &data, portMAX_DELAY); // xQueue就是this指针
3. LVGL(开源GUI库)
// 基础对象结构体
typedef struct _lv_obj_t {struct _lv_obj_t * parent; /*< 父对象指针 */lv_ll_t child_ll; /*< 子对象链表 */// 样式、事件等成员lv_style_list_t style_list;lv_signal_cb_t signal_cb; /*< 信号回调 */lv_design_cb_t design_cb; /*< 设计回调 */// ... 其他成员
} lv_obj_t;// 方法实现 - 第一个参数总是对象指针
void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
{// obj 就是 this 指针if(obj->coords.x2 - obj->coords.x1 + 1 == w && obj->coords.y2 - obj->coords.y1 + 1 == h) return;lv_obj_set_width(obj, w);lv_obj_set_height(obj, h);
}// 使用
lv_obj_t * btn = lv_btn_create(lv_scr_act(), NULL);
lv_obj_set_size(btn, 100, 50); // btn作为this指针传入
4. Contiki-NG(开源物联网OS)
// 传感器驱动结构体
struct sensors_sensor {char *name; /*< 传感器名称 */int (* value)(int type); /*< 读取数值方法 */int (* configure)(int type, int value); /*< 配置方法 */int (* status)(int type); /*< 状态查询方法 */
};// 具体传感器实现
static int tmp102_value(int type)
{// 通过全局变量或参数获取"this"信息// 在实际使用中,通常会传递设备上下文指针return read_temperature();
}// 传感器实例
SENSORS_SENSOR(tmp102_sensor, "TMP102", tmp102_value, tmp102_configure, tmp102_status);// 更现代的实现方式会使用上下文指针
typedef struct {i2c_dev_t *i2c_dev;uint8_t address;float last_temp;
} tmp102_t;int tmp102_read(tmp102_t *dev, float *temperature)
{// dev 就是 this 指针uint8_t buffer[2];i2c_read(dev->i2c_dev, dev->address, buffer, 2);// ... 温度计算dev->last_temp = calculated_temp;*temperature = calculated_temp;return 0;
}
5. Zephyr RTOS驱动模型
// 设备驱动操作结构体
struct uart_driver_api {int (*poll_in)(const struct device *dev, unsigned char *pChar);void (*poll_out)(const struct device *dev, unsigned char outChar);int (*err_check)(const struct device *dev);// ... 其他方法
};// 设备结构体
struct device {const char *name;const void *config; /*< 配置信息 */void * const data; /*< 数据 */const struct uart_driver_api *api; /*< 方法表 */
};// 方法调用宏(隐藏this指针传递)
#define uart_poll_out(dev, outChar) \((const struct uart_driver_api *)(dev)->api)->poll_out((dev), (outChar))// 实际实现
static void uart_nrfx_poll_out(const struct device *dev, unsigned char outChar)
{// dev 就是 this 指针const struct uart_nrfx_config *config = dev->config;nrf_uart_t *uart = config->uart;nrf_uart_txd_set(uart, outChar);// ... 实现细节
}// 使用
const struct device *uart_dev = device_get_binding("UART_0");
uart_poll_out(uart_dev, 'A'); // 隐式传递dev作为this指针
6. 嵌入式中间件 - Paho MQTT
// MQTT客户端结构体
typedef struct {char* serverURI; /*< 服务器地址 */int socket; /*< 网络套接字 */int (*connect)(void* client, MQTTPacket_connectData* options);int (*publish)(void* client, const char* topicName, MQTTMessage* message);int (*subscribe)(void* client, const char* topicFilter, enum QoS requestedQoS);// ... 其他方法和成员
} MQTTClient;// 方法实现
int MQTTConnect(void* client, MQTTPacket_connectData* options)
{MQTTClient* mqttClient = (MQTTClient*)client; // this指针转换// 使用mqttClient->socket等成员return network_connect(mqttClient->socket, mqttClient->serverURI);
}// 使用
MQTTClient client;
client.serverURI = "tcp://localhost:1883";
client.connect(&client, &connect_data); // 显式传递this指针
总结
差异原因
-
C++:编译器自动处理this指针,方法天然知道所属对象
-
C模拟:必须显式传递结构体指针作为"this"参数
-
函数指针:结构体中的函数指针只是指向函数,不包含对象信息
模拟特点
-
结构体作为类:包含数据成员和函数指针
-
显式this指针:总是作为方法的第一个参数
-
类型安全:通过void*转换或具体类型指针
-
封装性:通过头文件分离接口和实现
-
多态支持:通过函数指针表实现运行时绑定