C語言一點五編程實戰:純 C 的模塊化×繼承×多態框架
本文將大量涉及C語言高級操作,如函數指針、結構體指針、二級指針、指針頻繁引用解引用、typedef、static、inline和C語言項目結構等知識,請確保自己不會被上述知識沖擊,如果沒有這顧慮,請盡情享受~
摘要:
本文探討在C語言中模擬面向對象編程(OOP)的"一點五編程"技術,通過函數指針、結構體嵌套和二級指針強制轉換實現類、接口與多態。開發流程分聲明(接口/類結構體、類型轉換函數)、實現(方法綁定、初始化)和使用三階段,強調方法集指針必須位于類結構體首地址以實現動態綁定。該方法將硬件驅動與業務邏輯解耦,結合嵌入式場景展示模塊化設計,附偽實現循跡小車項目驗證繼承特性,為C語言賦予OOP的封裝性、擴展性,提升嵌入式代碼可維護性。
淵源
一開始時候,我是不知道這個技術的。在某一天我在刷B站的時候,看到一個作者為“一點五編程”的視頻。他提出了一種編程思想,命名為“一點五編程”。其中:
"一"指的是模塊化思想
“點五”指的是(*p)->f(p)技巧
我一看,好像是一種高端的技巧哇,于是開始看他的視頻,發現講解這一技術核心的視頻全都是充電的!!!好吧,那我只好翻你文檔看了,找到了他的個人博客。唔,好像什么都寫了,但好像少點什么,,,哦,沒教我到底怎么組織文件。
然后我繼續翻網頁,在CSDN上發現三篇文章,講的是對“一點五編程”的解讀。但是后來在自己實操過程中,還是發現了其中的錯誤。
看了這么多文章和視頻,腦子一拍,這不就是面向對象的編程范式嗎,只不過C語言是面向過程的語言,沒有現成的面向對象的組件,但是思想上完全就是OOP那套嘛!
于是我開始自己扒,終于,也是讓我扒出來了~
在文章的最后我會放上一個循跡小車的項目,當然,功能上偽實現(狗頭),那接下來先講下這門技術的基本理論和開發流程吧
理論
面向對象編程
我們先來說一下面向對象編程是什么:
面向對象編程是一種編程范式,它通過定義類和對象來組織和設計程序。
在面向對象編程中,程序猿通過創建類來定義數據結構和行為,通過創建對象來實例化這些類,并通過對象之間的交互來實現程序的功能。這種方法使得程序的結構更加清晰和易于維護。
面向對象編程有幾個特性,分別是:封裝、繼承、多態、抽象,這里就不再說了,只要知道本文會體現就行,(糾結)因為畢竟還是挺難理解的,我也講不明白,可以看看別的大佬的文章。
為什么要把面向對象編程拉出來說呢?眾所眾知,嵌入式是一個軟硬件結合的學科,這就會存在一個問題,就是我們會非常在乎硬件的實現,上層的功能實現就實現了,也不會在乎開發的結構、后期的維護等,這一點在初學者身上體現的淋漓盡致。
而面向對象編程就致力于讓程序更加模塊化,通過繼承和多態,使得大量代碼復用,它還有模擬現實世界中對象和關系的能力。這樣,就為開發者提供了一種自頂向下的開發思路。同時,它將上層實現與下層驅動相隔離,讓更換開發平臺變得簡單。
流程
我將整個C語言面向對象編程的開發分為三個階段,分別是聲明、實現和使用。
聲明
聲明階段又可以分為五個步驟,這些都是在頭文件中寫入的,分別是:
- 聲明接口函數
- 定義接口結構體
- 定義類結構體
- 定義類型轉換內聯函數
- 聲明方法實例
其中,聲明接口函數、定義接口結構體和定義類型轉換內聯函數僅需書寫一次,另外兩個步驟可以根據實際需求定義更多的類和方法實例。
聲明接口函數
在這里,接口就是類的行為方法集,控制整個類的行為方式。以循跡模塊為例,讀取循跡信息就是它的一個行為;以電機驅動模塊為例,控制電機停轉、正轉、反轉和控制轉動速度就是它的一系列行為。我們首先要思考我們所抽象出的類有哪些行為方法,寫成下面形式:
typedef int (*Method0FnT)(void* self, ...);
typedef int (*Method1FnT)(void* self, ...);
.
.
.
typedef int (*MethodnFnT)(void* self, ...);
定義接口結構體
接下來,我們要將上面的接口函數放到一個接口結構體中,方便由各個類使用:
typedef struct
{
Method0FnT method0Fn;
Method1FnT method1Fn;
.
.
.
MethodnFT methodnFn;
} MethodsT;
定義類結構體
完成上面步驟后,一個類的方法集就總結好了,再由方法集和類的各個屬性組成完整的類,這里一定要注意,方法集指針一定要放在類結構體的第一個,否則會出現錯誤:
typedef struct
{
MethodsT* methods;
Type attribute0;
Type attribute1;
.
.
.
Type attributen;
} Class;
定義類型轉換內聯函數
這里是我們實現多態這一特性最核心的步驟,寫成如下格式:
static inline int method0Fn(void* self, ...)
{
return (*(MethodsT**)self)->method0Fn(self, ...);
}
static inline int method1Fn(void* self, ...)
{
return (*(MethodsT**)self)->method1Fn(self, ...);
}
.
.
.
static inline int methodnFn(void* self, ...)
{
return (*(MethodsT**)self)->methodnFn(self, ...);
}
使用上面的語句,我們能夠將(*p)->f(p)改寫為f(p)的形式,而且不需要管類的具體函數實現。這里我們將指向類的一級指針強制類型轉換為指向接口的二級指針,再解引用就得到了一個僅指向接口的一級指針,再用成員訪問符使用接口函數。
這個過程中,要將指向類的一級指針強制類型轉換為指向接口的二級指針,就需要類的起始地址與接口的起始地址相同,也就是為什么上面說方法集的指針一定要放在類結構體的第一個,這樣指向接口的二級指針解引用后才會指向接口。
聲明方法實例
上面定義了抽象的接口和類,該到這個接口函數的具體實現了,當然,還要寫上類初始化函數的聲明:
int classMethod0(void* self, ...);
int classMethod1(void* self, ...);
.
.
.
int classMethodn(void* self, ...);
int classInit(void* self, ...);
實現
頭文件內容就完成了,下面是具體的相關函數的實現了,下面部分都在源文件中寫入,分為三個步驟:
- 定義方法實例
- 定義接口實例
- 定義類初始化函數
三個步驟的內容均由頭文件中的聲明限制。
定義方法實例
方法的實例我們已經在頭文件中聲明過了,在這里我們進行這些方法實例的定義:
int classMethod0(void* self, ...);
{
Class* pClass= (Class*)self;
//具體內容實現
//異常處理
return 1;
}
int classMethod1(void* self, ...)
{
Class* pClass= (Class*)self;
...
return 1;
}
.
.
.
int classMethodn(void* self, ...)
{
Class* pClass= (Class*)self;
...
return 1;
}
定義接口實例
具體的方法已經有了,接下來我們要實現具體的接口了,將方法實例的函數指針傳入到接口結構體中:
static MethodsT classMethods=
{
.method0Fn= classMethod0,
.method1Fn= classMethod1,
.
.
.
.methodnFn= classMethodn
}
定義類的初始化函數
最后我們編寫所需類的初始化的函數,類的屬性值將通過初始化函數傳入:
int classInit(void* self, ...)
{
Class* pClass= (Class*)self;
pClass->methods= &classMethods;
pClass->attribute0= ...;
pClass->attribute1= ...;
.
.
.
pClass->attributen= ...;
//其他初始化內容
//異常處理
return 1;
}
使用
使用起來就簡單了,首先我們要生成類的實例,然后使用初始化函數進行類初始化,然后,使用!
//生成實例可以放在main.h中或者主函數前或者主函數開頭
Class class
//初始化要放在開頭
classInit(&class, ...);
//使用方法就放在任何你需要其執行的地方即可
method0Fn(&class, ...);
method1Fn(&class, ...);
.
.
.
methodnFn(&class, ...);
就這樣,我們的所有功能就實現啦,我相信你一定學會了!(狗頭)
附錄
循跡小車的偽實現,會體現出上面沒有提及的繼承特性,見本倉庫:
https://github.com/swfeiyu/coop

關于我們更多介紹可以查看云文檔:Freak嵌入式工作室云文檔,或者訪問我們的wiki:https://github.com/leezisheng/Doc/wik


本文探討在C語言中模擬面向對象編程(OOP)的"一點五編程"技術,通過函數指針、結構體嵌套和二級指針強制轉換實現類、接口與多態。開發流程分聲明(接口/類結構體、類型轉換函數)、實現(方法綁定、初始化)和使用三階段,強調方法集指針必須位于類結構體首地址以實現動態綁定。該方法將硬件驅動與業務邏輯解耦,結合嵌入式場景展示模塊化設計,附偽實現循跡小車項目驗證繼承特性,為C語言賦予OOP的封裝性、擴展性,提升嵌入式代碼可維護性。

浙公網安備 33010602011771號