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

純C語言模擬C++虛函數表實現多態

     編輯:關於C

多態與面向接口編程並非C++專有,純C語言同樣可以通過函數指針與結構體嵌套模擬虛函數表機制,實現運行時多態。本文通過一個「動物-狗/貓」的經典繼承體系,詳細演示如何在C中手工構建虛表、綁定虛表指針、實現多態調用。

核心原理

  1. 虛表:一個包含虛函數指針的結構體,編譯期確定,每個類一份。
  2. 虛表指針:每個對象實例包含一個指向其類虛表的指針(_vptr),構造函數中綁定。
  3. 多態調用:通過基類指針訪問 _vptr,再調用虛表中的函數指針,實現動態綁定。

代碼結構

1. 基類 Animal(animal.h)

#ifndef ANIMAL_H
#define ANIMAL_H

/* 虛函數表結構:定義所有虛函數指針 */
typedef struct vtable {
    void (*eat)();
    void (*bite)();
} vtable;

/* 基類對象結構:包含虛表指針 */
typedef struct Animal {
    const vtable *_vptr;  // 指向具體子類的虛表
} Animal;

#endif

2. 子類 Dog(dog.h / dog.c)

/* dog.h */
#ifndef DOG_H
#define DOG_H
#include "animal.h"

typedef struct Dog {
    Animal base_obj;  // 基類子對象(必須放在第一位)
    int x;            // 子類自有數據
} Dog;

Animal* create_dog();  // 構造函數
#endif
/* dog.c */
#include 
#include 
#include "dog.h"

static void dog_eat() { printf("dog_eat()\n"); }
static void dog_bite() { printf("dog_bite()\n"); }

/* 編譯期確定的 Dog 虛表 */
static const vtable dog_vtable = { dog_eat, dog_bite };

Animal* create_dog() {
    Dog *pDog = (Dog*)malloc(sizeof(Dog));
    if (pDog) {
        pDog->base_obj._vptr = &dog_vtable;  // 運行時綁定虛表
        pDog->x = 0;
    }
    return (Animal*)pDog;  // 向上轉型返回基類指針
}

3. 子類 Cat(cat.h / cat.c)

/* cat.h */
#ifndef CAT_H
#define CAT_H
#include "animal.h"

typedef struct Cat {
    Animal base_obj;
    float y;
} Cat;

Animal* create_cat();
#endif
/* cat.c */
#include 
#include 
#include "animal.h"
#include "cat.h"

static void cat_eat() { printf("cat_eat()\n"); }
static void cat_bite() { printf("cat_bite()\n"); }

static const vtable cat_vtable = { cat_eat, cat_bite };

Animal* create_cat() {
    Cat *pCat = (Cat*)malloc(sizeof(Cat));
    if (pCat) {
        pCat->base_obj._vptr = &cat_vtable;
        pCat->y = 0.0f;
    }
    return (Animal*)pCat;
}

4. 主程序測試多態(main.c)

#include 
#include "animal.h"
#include "dog.h"
#include "cat.h"

/* 面向基類接口編程 */
void ShowBite(Animal *pAnimal) {
    pAnimal->_vptr->bite();  // 動態綁定調用
}

int main() {
    ShowBite(create_dog());  // 輸出: dog_bite()
    ShowBite(create_cat());  // 輸出: cat_bite()
    return 0;
}

關鍵技術點解析

技術點C++ 實現C 模擬實現
虛表存儲編譯器自動生成,存放在只讀數據段手工定義 static const vtable
虛表指針編譯器隱式添加到類對象首部手工在結構體首部添加 _vptr
構造函數綁定編譯器自動插入綁定代碼在 create_xxx() 中手工賦值
繼承關係語言級支持結構體嵌套:基類子對象放第一位
多態調用ptr->func()ptr->_vptr->func()

內存佈局圖解

Dog 對象內存佈局:
+------------------+
| _vptr -----------|----> dog_vtable { dog_eat, dog_bite }
+------------------+
| x (int)          |
+------------------+

Animal 基類子對象佔據 Dog 對象的前 sizeof(Animal) 字節,實現向上轉型時地址不變。

總結

純C模擬C++虛函數表,本質是將隱式的編譯器行為顯式化:手工定義虛表、在對象中存放虛表指針、構造時綁定、調用時通過指針間接跳轉。這不僅加深了對C++多態底層機制的理解,也為C語言項目引入面向對象設計提供了可行路徑。實際項目中,可進一步封裝宏簡化虛表定義與綁定代碼。

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