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

C语言对象模型系列(二)从函数指针到虚函数表:彻底理解 C 的多态—— 为什么 device->ops->open() 看起来像 C++?

一、上一篇留下的最大问题上一篇C语言对象模型系列一为什么 Linux / Android 系统里全是 struct 函数指针—— 一篇讲透 C 语言如何实现面向对象OOP我们提到device-ops-open();这种代码在Linux 内核Android HAL驱动JNIFFmpeg里到处都是。很多人第一次看到都会懵“这不是 C 吗”“为什么像对象调用方法一样”其实这一切的核心都是函数指针。而函数指针背后本质上就是C 语言的“多态”。二、先理解什么叫“多态”很多人学 Java 时Animal animal new Dog(); animal.run();觉得很自然。但其实这里发生了一件极其重要的事“同一个调用运行时决定具体执行哪个函数。”比如animal.run();真正执行的是Dog.run();而不是Animal.run();这就叫运行时动态分发Dynamic Dispatch也就是多态Polymorphism三、C 为什么没有多态因为 C 没有virtualclassoverridevtable所以run();在编译期就确定了。也就是说C 默认是静态调用。四、但大型系统一定需要“动态调用”比如不同驱动摄像头驱动 蓝牙驱动 GPS驱动都有open() close() read() write()但实现不同。如果这样写if(type CAMERA){ camera_open(); }else if(type BLUETOOTH){ bluetooth_open(); }会发生什么switch-case 地狱问题耦合严重扩展困难新增设备必须修改原代码这不符合开闭原则OCP于是Linux 内核工程师想到了“把函数当数据存起来。”这就是函数指针。五、函数指针到底是什么普通变量int a 10;保存的是数据。而函数void test(){}其实也有地址。函数名本质就是函数地址。比如void hello(){ printf(hello); }函数地址hello于是可以用变量保存函数地址。六、最基础的函数指针定义void (*func)(void);看起来很吓人。其实拆开部分含义void返回值(*func)func是指针(void)参数意思func 是一个“指向函数”的指针。赋值func hello;调用func();或者(*func)();都可以。七、现在开始进入“C 的多态”第一步定义统一接口typedef struct { void (*open)(void); void (*close)(void); } DeviceOps;看到没有这里函数指针被放进 struct 了。这时候struct function pointer开始像“对象 方法表”了。八、不同设备绑定不同实现摄像头void camera_open(){ printf(camera open); }蓝牙void bluetooth_open(){ printf(bluetooth open); }然后DeviceOps camera_ops { .open camera_open }; DeviceOps bluetooth_ops { .open bluetooth_open };九、真正的关键来了定义设备typedef struct { DeviceOps* ops; } Device;绑定Device camera { .ops camera_ops };调用camera.ops-open();输出camera open再换Device bluetooth { .ops bluetooth_ops };调用bluetooth.ops-open();输出bluetooth open看到没有同样的调用device-ops-open();运行时执行不同函数。这就是C 语言版多态。这其实就是“虚函数表”很多人学 C 时class Animal { virtual void run(); };觉得 virtual 很神秘。其实底层本质和上面一模一样。C 编译器偷偷帮你生成对象 ↓ vptr ↓ vtable ↓ 函数地址而 C是工程师自己手写。所以device-ops-open();本质其实就是对象 ↓ 函数表 ↓ 具体函数这就是虚函数表vtable的核心思想。十、为什么 Linux 特别喜欢这种设计因为它极其适合“统一接口不同实现”例如file_operationsLinux 内核经典结构struct file_operations { int (*open)(struct inode*, struct file*); ssize_t (*read)(struct file*, char*, size_t); };不同驱动read不同open不同但内核调用方式统一。Android HAL 也是一样比如camera module gps module audio moduleFramework 根本不关心你是高通MTK海思它只管module-open();十一、为什么这种设计比 switch-case 更高级因为它实现了“行为和类型解耦”以前类型决定行为现在函数表决定行为于是新增功能不需要改原代码。这就是开闭原则OCP十二、callback 本质也是这个思想很多人学setOnClickListener()觉得只是“回调”。其实callback 本质也是函数指针。比如void on_click(){ printf(clicked); }注册button-callback on_click;触发button-callback();本质“运行时决定调用哪个函数”依然是多态。十三、现在再回头看 JNI经典 JNI(*env)-CallVoidMethod()是不是突然顺眼了因为JNIEnv 本质就是函数表。也就是说env ↓ 函数表 ↓ CallVoidMethod这和device-ops-open();本质完全一致。十四、一句话总结函数指针让函数“可以像数据一样传递”而struct 函数指针则让 C拥有了“运行时动态分发能力”。这就是C语言实现多态的核心。十五、最后现在再回头看device-ops-open();你会发现它已经不是“调用函数”而是“对象通过函数表调用行为”了。所以很多 Linux / Android 系统代码虽然写的是 C但背后其实已经是完整的 OOP 思维。下一篇《JNIEnv 为什么是二级指针本质就是函数表》下一篇我们正式进入 JNI。彻底讲透(*env)-CallVoidMethod()为什么长这样。以及JNIEnv 为什么像对象为什么 JNI 到处是二级指针Java 和 Native 如何互调JNI 为什么本质是 C 风格 OOP真正把AndroidJVMNativeC对象模型全部串起来。

相关文章:

C语言对象模型系列(二)从函数指针到虚函数表:彻底理解 C 的多态—— 为什么 device->ops->open() 看起来像 C++?

一、上一篇留下的最大问题 上一篇: C语言对象模型系列(一)为什么 Linux / Android 系统里全是 struct 函数指针?—— 一篇讲透 C 语言如何实现面向对象(OOP) 我们提到: device->ops->…...

如何在Linux系统上使用SOLIDWORKS:完整指南与Wine兼容层解决方案

如何在Linux系统上使用SOLIDWORKS:完整指南与Wine兼容层解决方案 【免费下载链接】SOLIDWORKS-for-Linux This is a project, where I give you a way to use SOLIDWORKS on Linux! 项目地址: https://gitcode.com/gh_mirrors/so/SOLIDWORKS-for-Linux 你是…...

基于Cloudflare Workers的Gemini模型OpenAI API兼容代理部署指南

1. 项目概述:将Google Gemini模型桥接到OpenAI生态 如果你和我一样,既想体验Google Gemini 2.5系列模型强大的推理和视觉能力,又早已习惯了OpenAI API那套简洁、标准化的调用方式,那么你肯定也遇到过“生态割裂”的烦恼。每次想用…...

Rimworld Mod制作入门:从零搭建你的第一个功能Mod

1. 为什么选择Rimworld Mod开发 Rimworld作为一款深度沙盒游戏,其魅力很大程度上来自于丰富的Mod生态。你可能已经玩过不少别人制作的Mod,但有没有想过自己动手创造一个?我刚开始接触Mod开发时也觉得很复杂,但实际尝试后发现&…...

FFmpeg GUI终极指南:告别命令行,图形化音视频处理如此简单

FFmpeg GUI终极指南:告别命令行,图形化音视频处理如此简单 【免费下载链接】ffmpegGUI ffmpeg GUI 项目地址: https://gitcode.com/gh_mirrors/ff/ffmpegGUI 还在为复杂的FFmpeg命令行参数而头疼吗?FFmpeg GUI将彻底改变你的音视频处理…...

三相锁相环在DSP(如TI C2000)上的移植与调试避坑指南

三相锁相环在TI C2000 DSP上的工程化实现与调试实战 对于电力电子工程师而言,将理论算法转化为实际可运行的硬件代码往往是最具挑战性的环节。当您已经理解了三相锁相环(SPLL)的数学原理,手头也有了核心算法的C语言实现,接下来要面对的才是真…...

NS-USBLoader终极指南:3种高效管理Switch游戏传输的完整解决方案

NS-USBLoader终极指南:3种高效管理Switch游戏传输的完整解决方案 【免费下载链接】ns-usbloader Awoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files. 项目地址: https://gitcode.co…...

WindowResizer:Windows窗口调整的终极免费工具,让每个窗口都听你指挥

WindowResizer:Windows窗口调整的终极免费工具,让每个窗口都听你指挥 【免费下载链接】WindowResizer 一个可以强制调整应用程序窗口大小的工具 项目地址: https://gitcode.com/gh_mirrors/wi/WindowResizer 还在为那些固执的Windows窗口而烦恼吗…...

北航毕业论文LaTeX模板终极指南:三步快速搞定格式规范

北航毕业论文LaTeX模板终极指南:三步快速搞定格式规范 【免费下载链接】BUAAthesis 北航毕设论文LaTeX模板 项目地址: https://gitcode.com/gh_mirrors/bu/BUAAthesis 还在为北航毕业论文格式要求头疼吗?手动调整页眉页脚、参考文献编号、目录格式…...

打造你的专属数字伙伴:3步开启桌面宠物创作之旅 [特殊字符]

打造你的专属数字伙伴:3步开启桌面宠物创作之旅 🎨 【免费下载链接】DyberPet Desktop Cyber Pet Framework based on PySide6 项目地址: https://gitcode.com/GitHub_Trending/dy/DyberPet 你是否曾经梦想过在单调的电脑桌面上拥有一个会动、会互…...

基于AI智能体的Telegram到Obsidian自动化知识管理方案

1. 项目概述:用AI构建你的第二大脑,从手机到知识库的无缝流转 你有没有过这样的时刻?在手机上刷到一篇深度好文,或者看到一个精彩的YouTube视频,脑子里闪过一个绝妙的点子,你对自己说:“这个得…...

5分钟掌握B站4K视频下载:开源工具完全指南

5分钟掌握B站4K视频下载:开源工具完全指南 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 还在为无法保存B站精彩视频而烦…...

嵌入式实战 | 51单片机驱动TEA5767 FM收音机,从I²C通信到1602液晶显示

1. 项目背景与硬件选型 第一次用51单片机做FM收音机时,我对着淘宝上五花八门的收音模块发愁。直到发现TEA5767这个宝藏芯片——它把高频接收、中频处理、音频解调全部集成在指甲盖大小的封装里,连立体声解码都帮你做好了。这种"傻瓜式"解决方案…...

手把手教你为Rockchip Buildroot添加自定义软件包(附CMake/Makefile实例)

手把手教你为Rockchip Buildroot添加自定义软件包(附CMake/Makefile实例) 在嵌入式Linux开发中,Buildroot因其高度定制化和轻量级特性成为Rockchip平台的热门选择。但当你需要集成自己的驱动程序或应用程序时,官方文档往往显得过于…...

告别繁琐手动切割:Pixelorama智能精灵图切割让效率提升90%

告别繁琐手动切割:Pixelorama智能精灵图切割让效率提升90% 【免费下载链接】Pixelorama Unleash your creativity with Pixelorama, a powerful and accessible open-source pixel art multitool. Whether you want to create sprites, tiles, animations, or just …...

基于XGBoost与神经网络的NBA赛果预测:从数据采集到凯利公式下注

1. 项目概述:用机器学习预测NBA赛果与盘口如果你对NBA比赛和数据分析都感兴趣,那么把两者结合起来,用机器学习模型来预测比赛胜负和总分盘口(大小分),无疑是一件极具吸引力的事情。这不仅仅是简单的数据堆砌…...

如何永久保存微信聊天记录?本地免费工具WeChatMsg终极指南

如何永久保存微信聊天记录?本地免费工具WeChatMsg终极指南 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/W…...

5分钟快速上手:在Blender中使用3MF格式的完整指南

5分钟快速上手:在Blender中使用3MF格式的完整指南 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 你是否厌倦了在Blender和3D打印软件之间来回切换的繁琐流程…...

Navicat Mac版试用期重置终极指南:3种简单方法无限使用

Navicat Mac版试用期重置终极指南:3种简单方法无限使用 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_mac 还在为Nav…...

深度实战:如何用SpliceAI深度学习工具精准预测基因剪接变异

深度实战:如何用SpliceAI深度学习工具精准预测基因剪接变异 【免费下载链接】SpliceAI A deep learning-based tool to identify splice variants 项目地址: https://gitcode.com/gh_mirrors/sp/SpliceAI 想要在遗传变异研究中获得准确的剪接影响预测吗&…...

yuzu模拟器完整指南:免费在电脑上玩Switch游戏的终极教程

yuzu模拟器完整指南:免费在电脑上玩Switch游戏的终极教程 【免费下载链接】yuzu 任天堂 Switch 模拟器 项目地址: https://gitcode.com/GitHub_Trending/yu/yuzu yuzu是目前最受欢迎的免费开源任天堂Switch模拟器,让你能在Windows、Linux和Androi…...

利用AI生成专业README:告别文档焦虑,提升项目协作效率

1. 项目概述:告别文档焦虑,用AI生成专业README每次新建一个项目,或者接手一个半成品,最头疼的是什么?对我而言,除了写代码本身,就是面对那个空荡荡的README.md文件。我知道它很重要——它是项目…...

AI Agent赋能非车险产品开发:开源知识库与自动化流程实践

1. 项目概述:一个面向AI Agent的非车险产品开发知识库在保险行业,尤其是财产险领域,产品开发一直是一项高度专业化且流程复杂的工作。传统的非车险产品开发,从市场调研、风险识别、条款撰写、费率厘定到监管报备,往往需…...

如何3步掌握图表数据提取:WebPlotDigitizer让科研数据重获新生

如何3步掌握图表数据提取:WebPlotDigitizer让科研数据重获新生 【免费下载链接】WebPlotDigitizer Computer vision assisted tool to extract numerical data from plot images. 项目地址: https://gitcode.com/gh_mirrors/we/WebPlotDigitizer 你是否曾面对…...

智能制造系统中的物理因子有哪些

在智能制造系统的工业机理建模中,物理因子(Physical Factors)是指那些描述生产过程、设备状态及环境变化的物理变量。根据其在生产中的作用,通常可以归纳为以下五大类: 1. 动力学与力学因子(机器的“骨架”…...

终极指南:如何用WebPlotDigitizer让图表数据“开口说话“ - 科研数据提取的革命性工具

终极指南:如何用WebPlotDigitizer让图表数据"开口说话" - 科研数据提取的革命性工具 【免费下载链接】WebPlotDigitizer Computer vision assisted tool to extract numerical data from plot images. 项目地址: https://gitcode.com/gh_mirrors/we/Web…...

5分钟快速上手:浏览器中直接查看SQLite数据库的终极免费工具

5分钟快速上手:浏览器中直接查看SQLite数据库的终极免费工具 【免费下载链接】sqlite-viewer View SQLite file online 项目地址: https://gitcode.com/gh_mirrors/sq/sqlite-viewer 想象一下这样的场景:你刚刚收到同事发来的一个SQLite数据库文件…...

深度解析B站视频下载器:技术架构与实战应用指南

深度解析B站视频下载器:技术架构与实战应用指南 【免费下载链接】bilibili-downloader B站视频下载,支持下载大会员清晰度4K,持续更新中 项目地址: https://gitcode.com/gh_mirrors/bil/bilibili-downloader 在数字内容消费日益增长的…...

AI驱动CD流水线性能跃迁:实测QPS提升3.8倍、部署失败率下降92.6%的5个核心改造点

更多请点击: https://intelliparadigm.com 第一章:AI原生持续交付:2026奇点智能技术大会部署流水线优化 在2026奇点智能技术大会上,AI原生持续交付(AI-Native CI/CD)成为核心实践范式——它不再将AI模型视…...

Docker容器网络详解+端口映射原理(系列第二篇:实战核心)

文章目录 前言一、Docker网络核心认知(必须先懂)1 容器的隔离本质2 Docker默认自带三大网络 二、四大网络模式超通俗详解(含适用场景)1、bridge 桥接模式(默认模式、最常用)2、host 主机模式(无…...