首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言模擬 C++ 繼承與多態:VTable 函數指針表、基類/派生類交叉引用

     編輯:關於C

核心思想

C 無原生類/繼承/多態,但可用 **結構體 + 函數指針 + 手動 VTable** 模擬。

基類 Person

typedef struct Person Person;
typedef void (*DisplayFn)(Person*);
typedef void (*WriteFn)(Person*, const char*);
typedef void (*DeleteFn)(Person*);

struct Person {
    void *derived;     // 指向派生對象 (多態關鍵)
    char *first_name;
    char *last_name;
    DisplayFn display;
    WriteFn write;
    DeleteFn del;
};

Person* new_Person(const char* fn, const char* ln) {
    Person *p = malloc(sizeof(Person));
    p->derived = p; // 基類指向自己
    p->first_name = strdup(fn);
    p->last_name = strdup(ln);
    p->display = Person_Display;
    p->write = Person_Write;
    p->del = delete_Person;
    return p;
}

void Person_Display(Person *p) { printf("Person: %s %s\n", p->first_name, p->last_name); }
void Person_Write(Person *p, const char* f) { /* ... */ }
void delete_Person(Person *p) { free(p->first_name); free(p->last_name); free(p); }

派生類 Employee

typedef struct Employee Employee;
struct Employee {
    Person *base;      // 指向基類部分
    char *dept;
    char *company;
    int salary;
};

Person* new_Employee(const char* fn, const char* ln,
                     const char* dept, const char* comp, int sal) {
    Person *p = new_Person(fn, ln); // 先建基類
    Employee *e = malloc(sizeof(Employee));
    e->base = p;
    e->dept = strdup(dept);
    e->company = strdup(comp);
    e->salary = sal;
    
    p->derived = e; // 基類 derived 指向派生對象
    // 覆寫 VTable (多態核心)
    p->display = Employee_Display;
    p->write = Employee_Write;
    p->del = delete_Employee; // 析構鏈
    return p;
}

void Employee_Display(Person *p) {
    Employee *e = (Employee*)p->derived;
    printf("Employee: %s %s, Dept: %s, Salary: %d\n",
           e->base->first_name, e->base->last_name, e->dept, e->salary);
}
void delete_Employee(Person *p) {
    Employee *e = (Employee*)p->derived;
    free(e->dept); free(e->company);
    delete_Person(p); // 呼叫基類析構
}

多態使用

int main() {
    Person *p1 = new_Person("Anjali", "Jaiswal");
    Person *p2 = new_Employee("Gauri", "Jaiswal", "HR", "TCS", 40000);
    
    p1->display(p1); // Person: Anjali Jaiswal
    p2->display(p2); // Employee: Gauri Jaiswal, Dept: HR, Salary: 40000
    
    p1->del(p1);
    p2->del(p2); // 自動呼叫 delete_Employee -> delete_Person
    return 0;
}

關鍵機制總結

  1. VTable:結構體內嵌函數指針 (display, write, del)。
  2. 交叉引用:基類 derived 指向派生,派生 base 指向基類。
  3. 構造鏈:派生構造先呼叫基類構造,再覆寫 VTable。
  4. 析構鏈:派生析構釋放自身資源,再呼叫基類析構。
  5. this 指針模擬:所有成員函數第一參數為 Person* (基類指針),透過 derived 存取派生資料。

現代 C 替代:C11 _Generic + 組合而非繼承

組合 (Composition) 通常比模擬繼承更符合 C 風格,避免複雜指針網。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved