// 錯誤嘗試:C 結構體不能直接包含函數體
struct Test {
void fun() { printf("hello"); } // 編譯錯誤!
};
// 正確:函數指標成員
struct Test {
void (*Fun)(void); // 指向函數的指標
};
void real_fun(void) { printf("hello world\n"); }
int main() {
struct Test t;
t.Fun = real_fun; // 綁定
t.Fun(); // 調用
return 0;
}
#include
struct MyClass {
char *name;
int age;
// 無參方法
void (*funnull)(void);
// 帶 this 指標的方法 (模擬 thiscall)
void (*func)(struct MyClass *this);
};
// 實際函數定義
void real_funnull(void) { printf("hello world!\n"); }
void real_func(struct MyClass *this) {
printf("MyClass's name is: %s\n", this->name);
printf("MyClass's age is: %d\n", this->age);
}
int main() {
// 構造對象:字面量初始化綁定方法
struct MyClass mc = {
"Simon", 25,
real_funnull,
real_func
};
mc.funnull(); // 靜態方法調用
mc.func(&mc); // 實例方法調用,手動傳 this
return 0;
}
關鍵點:C++ 隱式傳遞 this,C 需顯式傳遞。這就是「非虛函數」的調用本質。
// 定義操作集合 (類似 vtable)
struct file_operations {
int (*open)(struct inode *, struct file *);
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
int (*release)(struct inode *, struct file *);
};
// 具體實現
static int my_open(struct inode *inode, struct file *filp) { ... }
static ssize_t my_read(struct file *filp, char __user *buf, size_t len, loff_t *off) { ... }
// 綁定 (靜態常量,唯讀段)
static const struct file_operations my_fops = {
.open = my_open,
.read = my_read,
.write = my_write,
.release = my_release,
};
// 使用:文件系統層通過指標調用
filp->f_op->read(filp, buf, count, &pos);
這就是運行時多態:同一接口,不同實現,通過函數指標表分派。
struct Base {
int base_data;
void (*base_method)(struct Base *);
};
struct Derived {
struct Base base; // 組合作為第一個成員
int derived_data;
void (*derived_method)(struct Derived *);
};
// 向上轉換安全:Derived* → Base* (地址相同)
void call_base(struct Base *b) { b->base_method(b); }
int main() {
struct Derived d = { .base = { .base_data = 1 }, .derived_data = 2 };
call_base((struct Base*)&d); // 正常工作
return 0;
}
C++ 單繼承內存佈局正是如此:基類子對象在派生對象起始地址。
struct VTable_Shape {
void (*draw)(struct Shape *);
double (*area)(struct Shape *);
};
struct Shape {
struct VTable_Shape *vptr; // 虛表指標
// 通用數據...
};
// 具體類 Circle
struct Circle {
struct Shape base;
double radius;
};
void Circle_draw(struct Shape *s) { ... }
double Circle_area(struct Shape *s) { ... }
static struct VTable_Shape Circle_vtable = {
.draw = Circle_draw,
.area = Circle_area
};
void Circle_ctor(struct Circle *c, double r) {
c->base.vptr = &Circle_vtable; // 綁定虛表
c->radius = r;
}
// 多態調用
void draw_shape(struct Shape *s) { s->vptr->draw(s); }
這正是 C++ 編譯器為虛函數生成的代碼邏輯:vptr 指向類共享的 vtable,調用時間接跳轉。
| 特性 | C 手動實現 | C++ 原生支援 |
|---|---|---|
| 封裝 | 不透明指標 + 內部結構體定義在 .c | private/protected/public |
| 繼承 | 結構體組合 (基類作為首成員) | class Derived : Base |
| 多態 | 手動虛表指標 + 顯式 this 傳遞 | 虛函數、虛表、隱式 this |
| 構造/析構 | 手動 init()/destroy() | 構造函數/析構函數、RAII |
| 類型安全 | 靠程式員自律 | 編譯器強制檢查 |
| 代碼量 | 大量樣板代碼 | 語言級語法糖 |
struct Foo;,.c 定義完整結構,API 傳 Foo*。int 錯誤碼,輸出參數用指標。create()/destroy(),文檔明確所有權。