# 介绍 实现C面向对象写法: 1. `pointer`分支是基于函数指针的封装; 2. `opaque`分支是不透明结构体的封装。 # 与不透明结构体的对比 ## 1.基于函数指针的封装: - 优点: - 模拟面向对象编程,使用方便,调用简洁。 - 函数指针可以灵活替换,允许不同实例有不同的行为(类似于多态)。 - 代码更具可读性,通过对象访问函数使得代码显得更加面向对象。 - 缺点: - 增加了一定的复杂性,尤其是在初始化、管理函数指针和内存管理时。 - 效率上可能会有轻微的开销,因为每次调用都要通过函数指针间接调用实际函数。 - 函数指针可能导致调试变得更困难(比如在使用调试器时,无法直接看到函数调用链)。 ## 2.不透明结构体(Opaque Struct): - 优点: - 更简单和直接,库的用户不需要关心结构体内部的实现细节,增加了封装性和代码的安全性。 - 函数调用时更加直观,通过全局函数操作对象,用户只看到需要操作的API接口。 - 减少了复杂性,尤其在内存管理和函数指针管理方面更为轻量。 - 缺点: - 不能模拟对象方法调用,调用方式可能显得不够“面向对象”。 - 不支持多态:所有实例共享相同的函数,不能为不同实例设置不同的行为。 # 工程中的使用情况 在实际工程中,**不透明结构体(Opaque Struct)** 的方式通常使用得更多。 尤其是在系统编程、嵌入式开发或跨平台库设计中,不透明结构体是更常见的设计模式。 它的封装性好,内存管理相对简单,并且函数调用更加高效。 这种模式通常用于C库的设计,比如许多操作系统API和标准库都会采用这种模式。 ## 不透明结构体(Opaque Struct)的实际例子 1. POSIX标准中的文件操作(FILE 结构体): `FILE` 结构体就是一个经典的不透明结构体。 用户通过API函数如 `fopen()`, `fclose()`, `fread()`, `fwrite()` 操作 `FILE` 指针,但无法直接访问 `FILE` 结构体的内部实现。 ```c FILE* file = fopen("test.txt", "r"); if (file) { // 使用 fread、fwrite 等函数操作 FILE 对象 fclose(file); } ``` 2. OpenGL 的 GLFW 库: `GLFW` 是一个图形库,它大量使用了不透明结构体的设计。用户只能通过API函数操作这些结构体,如 `GLFWwindow`。 ```c GLFWwindow* window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL); if (window) { // 使用 glfwGetWindowSize 等函数操作 GLFWwindow glfwDestroyWindow(window); } ``` 3. libcurl `libcurl` 使用了不透明结构体,库的用户通过 `CURL`* 指针操作 HTTP 请求,而无法直接访问内部数据。 ```c CURL *curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://example.com"); curl_easy_perform(curl); curl_easy_cleanup(curl); } ``` ## 基于函数指针封装的实际例子 这种模式较少见于系统编程或者底层库设计,但在某些场景中,例如模拟面向对象编程、插件系统或者策略模式时,这种模式非常有用。 1. 插件系统(Plugin System): 在许多插件系统中,插件往往通过一个统一的结构体接口暴露函数指针。 这种设计可以允许不同的插件使用不同的行为,但又通过统一的接口进行交互。 例如,音频处理库 FFmpeg 中的一些模块设计就是通过函数指针进行交互。 ```c struct Plugin { void (*init)(void); void (*process)(void); void (*destroy)(void); }; ``` 2. `SDL(Simple DirectMedia Layer)`事件处理: 虽然SDL本身大多数时候使用不透明结构体,但在处理回调函数时,类似于函数指针的设计非常常见。 事件驱动系统通过将函数指针传递给SDL,可以自定义事件的处理逻辑。 ```c SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: quit(); break; case SDL_KEYDOWN: keydown(event.key.keysym.sym); break; } } ``` # 总结 - 不透明结构体(Opaque Struct) 是实际工程中更为常见的设计,特别是在需要跨平台和高效的API设计中。 - 基于函数指针的封装 更适合在需要模拟面向对象行为,或需要为不同对象提供不同实现的场景。 如果你的库需要高性能并且用户操作相对简单,`不透明结构体`是更合适的选择;而如果你希望提供面向对象的编程体验,可以考虑`基于函数指针的封装`。