C語言本身不支持類、繼承、多態等面向對象特性,但這並不意味著我們無法在C中應用面向對象設計思想。Linux內核、GTK+等經典項目均大量使用結構體配合函數指針,實現了封裝、繼承甚至多態。本文將從基礎語法限制切入,逐步展示如何用純C構建「對象化」架構。
嘗試在struct中直接定義函數會導致編譯錯誤:
#include <stdio.h>
struct test {
void fun() { printf("hello,world\n"); } // 錯誤:C結構體不允許成員函數
};
int main() {
struct test _t;
_t.fun();
return 0;
}
正確做法是聲明函數指針成員,並在運行時綁定具體函數:
#include <stdio.h>
void fun() { printf("hello,world\n"); }
struct test {
void (*Fun)(); // 函數指針成員
};
int main() {
struct test _t;
_t.Fun = fun; // 綁定函數
(*_t.Fun)(); // 調用
return 0;
}
為了讓成員函數能訪問對象自身數據,需將結構體指針作為第一個參數傳入(模擬C++的this):
#include <stdio.h>
struct MyClass {
char* name;
int age;
void (*funnull)();
void (*func)(struct MyClass* mc); // 參數為自身指針
};
void realfunnull() { printf("hello world!\n"); }
void realfunc(struct MyClass* mc) {
printf("MyClass's name is:%s\n", mc->name);
printf("MyClass's age is:%d\n", mc->age);
}
int main() {
struct MyClass mc = {"Simon", 25, realfunnull, realfunc};
mc.funnull();
mc.func(&mc); // 傳遞自身地址
return 0;
}
Linux源碼中廣泛採用「操作表」模式:將函數指針集中在一個struct xxx_operations中,數據結構僅持有指向操作表的指針。這實現了數據與行為的分離,支援運行時動態替換實現(如文件系統、驅動程序的多態)。
self指針模擬成員訪問