C++虚函数表机理详解与C语言实现

次浏览

概述

C++ 的多态是通过**虚函数表(Virtual Table, vtable)**实现的。理解 vtable 的工作原理,能让我们深入理解 C++ 的对象模型和多态机制。本文将从原理出发,最终用 C 语言模拟实现完整的虚函数表机制。


一、多态的底层原理

1.1 什么是多态?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Animal {
public:
    virtual void speak() { std::cout << "Animal speaks\n"; }
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void speak() override { std::cout << "Dog barks\n"; }
};

class Cat : public Animal {
public:
    void speak() override { std::cout << "Cat meows\n"; }
};

void make_sound(Animal* animal) {
    animal->speak();  // 运行时决定调用哪个函数
}

int main() {
    Dog dog;
    Cat cat;
    make_sound(&dog);  // 输出: Dog barks
    make_sound(&cat);  // 输出: Cat meows
}

问题:animal->speak() 是如何在运行时知道调用哪个函数的?

答案:虚函数表(vtable)和虚函数指针(vptr)

1.2 核心概念

概念 说明
vtable(虚函数表) 一个函数指针数组,存储类的所有虚函数地址
vptr(虚函数指针) 对象内部的隐藏指针,指向该类的 vtable
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
┌─────────────────────────────────────────────────────────┐
│                     内存布局                              │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   Dog 对象                    Dog 的 vtable             │
│  ┌──────────┐                ┌──────────────────────┐   │
│  │   vptr   │───────────────►│ &Dog::speak()        │   │
│  │ (继承的) │                │ &Animal::~Animal()   │   │
│  │  成员...  │                │ ...                  │   │
│  └──────────┘                └──────────────────────┘   │
│                                                         │
└─────────────────────────────────────────────────────────┘

二、虚函数表的内存布局

2.1 单继承的情况

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include <iostream>

class Base {
public:
    virtual void func1() { std::cout << "Base::func1\n"; }
    virtual void func2() { std::cout << "Base::func2\n"; }
    virtual void func3() { std::cout << "Base::func3\n"; }
    
    int data = 10;
};

class Derived : public Base {
public:
    void func1() override { std::cout << "Derived::func1\n"; }
    void func3() override { std::cout << "Derived::func3\n"; }
    // func2 未重写,继承 Base::func2
    
    int extra = 20;
};

内存布局分析:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Base 对象:
┌────────────┬──────────┐
│ vptr       │ data=10  │
└────────────┴──────────┘
Base vtable:
┌─────────────────┬─────────────────┬─────────────────┐
│ &Base::func1    │ &Base::func2    │ &Base::func3    │
└─────────────────┴─────────────────┴─────────────────┘

Derived 对象:
┌────────────┬──────────┬───────────┐
│ vptr       │ data=10  │ extra=20  │
└────────────┴──────────┴───────────┘
Derived vtable:
┌───────────────────┬─────────────────┬───────────────────┐
│ &Derived::func1   │ &Base::func2    │ &Derived::func3   │
└───────────────────┴─────────────────┴───────────────────┘

2.2 用代码验证内存布局

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <cstdint>

class Base {
public:
    virtual void func1() { std::cout << "Base::func1\n"; }
    virtual void func2() { std::cout << "Base::func2\n"; }
    int data = 0x11111111;
};

class Derived : public Base {
public:
    void func1() override { std::cout << "Derived::func1\n"; }
    int extra = 0x22222222;
};

// 函数指针类型
using FuncPtr = void(*)();

int main() {
    Derived d;
    
    // 1. 对象大小(vptr + data + extra)
    std::cout << "Size of Derived: " << sizeof(d) << " bytes\n";
    // 64位系统:8(vptr) + 4(data) + 4(padding) + 4(extra) + 4(padding) = 24 bytes
    
    // 2. 获取 vptr(对象起始地址就是 vptr)
    void** vptr = *(void***)(&d);
    std::cout << "vptr address: " << vptr << "\n";
    
    // 3. 遍历 vtable
    std::cout << "\n=== vtable contents ===\n";
    for (int i = 0; i < 2; i++) {
        std::cout << "vtable[" << i << "]: " << vptr[i] << "\n";
        // 调用虚函数
        FuncPtr func = (FuncPtr)vptr[i];
        func();
    }
    
    return 0;
}

输出:

1
2
3
4
5
6
7
8
Size of Derived: 16 bytes
vptr address: 0x...

=== vtable contents ===
vtable[0]: 0x...
Derived::func1
vtable[1]: 0x...
Base::func2

三、用 C 语言实现 vptr

现在我们用 C 语言模拟 C++ 的虚函数表机制。

3.1 基础结构定义

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdio.h>
#include <stdlib.h>

// 虚函数表结构:函数指针数组
typedef struct {
    void (*speak)(void* this);
    void (*destroy)(void* this);
    void (*eat)(void* this, const char* food);
} VTable;

// 基类结构
typedef struct {
    const VTable* vptr;  // 虚函数指针,指向类的 vtable
    const char* name;
    int age;
} Animal;

// 派生类结构(Dog)
typedef struct {
    Animal base;       // 基类部分(必须放在开头!)
    const char* breed; // 派生类特有成员
} Dog;

// 派生类结构(Cat)
typedef struct {
    Animal base;
    int lives;  // 猫有九条命
} Cat;

3.2 实现各类的虚函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// ========== Animal 的虚函数 ==========

void Animal_speak(void* this) {
    Animal* a = (Animal*)this;
    printf("%s makes a sound\n", a->name);
}

void Animal_eat(void* this, const char* food) {
    Animal* a = (Animal*)this;
    printf("%s eats %s\n", a->name, food);
}

void Animal_destroy(void* this) {
    Animal* a = (Animal*)this;
    printf("Animal %s is destroyed\n", a->name);
    free(this);
}

// Animal 的虚函数表
const VTable Animal_vtable = {
    .speak = Animal_speak,
    .destroy = Animal_destroy,
    .eat = Animal_eat
};

// ========== Dog 的虚函数 ==========

void Dog_speak(void* this) {
    Dog* d = (Dog*)this;
    printf("%s the %s barks: WOOF!\n", d->base.name, d->breed);
}

void Dog_eat(void* this, const char* food) {
    Dog* d = (Dog*)this;
    printf("%s the dog enthusiastically eats %s\n", d->base.name, food);
}

void Dog_destroy(void* this) {
    Dog* d = (Dog*)this;
    printf("Dog %s is destroyed\n", d->base.name);
    free(this);
}

// Dog 的虚函数表
const VTable Dog_vtable = {
    .speak = Dog_speak,
    .destroy = Dog_destroy,
    .eat = Dog_eat
};

// ========== Cat 的虚函数 ==========

void Cat_speak(void* this) {
    Cat* c = (Cat*)this;
    printf("%s meows: MEOW~ (has %d lives left)\n", c->base.name, c->lives);
}

void Cat_eat(void* this, const char* food) {
    Cat* c = (Cat*)this;
    printf("%s the cat elegantly eats %s\n", c->base.name, food);
}

void Cat_destroy(void* this) {
    Cat* c = (Cat*)this;
    printf("Cat %s is destroyed\n", c->base.name);
    free(this);
}

// Cat 的虚函数表
const VTable Cat_vtable = {
    .speak = Cat_speak,
    .destroy = Cat_destroy,
    .eat = Cat_eat
};

3.3 构造函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Animal 构造函数
Animal* Animal_new(const char* name, int age) {
    Animal* a = malloc(sizeof(Animal));
    a->vptr = &Animal_vtable;  // 设置 vptr 指向 Animal 的 vtable
    a->name = name;
    a->age = age;
    return a;
}

// Dog 构造函数
Dog* Dog_new(const char* name, int age, const char* breed) {
    Dog* d = malloc(sizeof(Dog));
    d->base.vptr = &Dog_vtable;  // 设置 vptr 指向 Dog 的 vtable
    d->base.name = name;
    d->base.age = age;
    d->breed = breed;
    return d;
}

// Cat 构造函数
Cat* Cat_new(const char* name, int age, int lives) {
    Cat* c = malloc(sizeof(Cat));
    c->base.vptr = &Cat_vtable;  // 设置 vptr 指向 Cat 的 vtable
    c->base.name = name;
    c->base.age = age;
    c->lives = lives;
    return c;
}

3.4 虚函数调用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 通过 vptr 调用虚函数(模拟 C++ 的虚函数调用)
void speak(Animal* a) {
    a->vptr->speak(a);  // this 指针必须显式传递
}

void eat(Animal* a, const char* food) {
    a->vptr->eat(a, food);
}

void destroy(Animal* a) {
    a->vptr->destroy(a);  // 虚析构函数!
}

3.5 完整示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int main() {
    printf("=== Creating objects ===\n");
    
    // 创建对象(自动设置正确的 vptr)
    Dog* dog = Dog_new("Buddy", 3, "Golden Retriever");
    Cat* cat = Cat_new("Whiskers", 5, 9);
    Animal* animal = Animal_new("Creature", 10);
    
    printf("\n=== Virtual function calls ===\n");
    
    // 多态调用!
    speak((Animal*)dog);   // Dog::speak
    speak((Animal*)cat);   // Cat::speak
    speak(animal);         // Animal::speak
    
    printf("\n=== More virtual calls ===\n");
    
    eat((Animal*)dog, "bones");
    eat((Animal*)cat, "fish");
    
    printf("\n=== Virtual destructor ===\n");
    
    // 虚析构函数演示
    Animal* animals[] = {
        (Animal*)dog,
        (Animal*)cat,
        animal
    };
    
    for (int i = 0; i < 3; i++) {
        destroy(animals[i]);  // 正确调用各自的析构函数
    }
    
    return 0;
}

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
=== Creating objects ===

=== Virtual function calls ===
Buddy the Golden Retriever barks: WOOF!
Whiskers meows: MEOW~ (has 9 lives left)
Creature makes a sound

=== More virtual calls ===
Buddy the dog enthusiastically eats bones
Whiskers the cat elegantly eats fish

=== Virtual destructor ===
Dog Buddy is destroyed
Cat Whiskers is destroyed
Animal Creature is destroyed

四、vtable 的高级特性

4.1 多重继承的 vtable

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class A {
public:
    virtual void f1() {}
    int a;
};

class B {
public:
    virtual void f2() {}
    int b;
};

class C : public A, public B {
public:
    void f1() override {}
    void f2() override {}
    virtual void f3() {}
    int c;
};

C 的内存布局:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
C 对象:
┌─────────────┬───────┬─────────────┬───────┬───────┐
│ vptr_A      │ a     │ vptr_B      │ b     │ c     │
└─────────────┴───────┴─────────────┴───────┴───────┘
      │                    │
      ▼                    ▼
┌───────────────┐    ┌───────────────┐
│ &C::f1        │    │ &C::f2        │
│ &C::~C()      │    │ thunk to C::f2│
│ &C::f3        │    └───────────────┘
└───────────────┘

多重继承时:

  • 每个基类有自己的 vptr
  • B 的 vtable 中有 thunk(调整 this 指针的小代码片段)

4.2 用 C 模拟多重继承

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// ========== 多重继承模拟 ==========

typedef struct {
    void (*f1)(void*);
} VTableA;

typedef struct {
    void (*f2)(void*);
} VTableB;

typedef struct {
    void (*f1)(void*);
    void (*f2)(void*);
    void (*f3)(void*);
} VTableC;

// 基类 A
typedef struct {
    const VTableA* vptr;
    int a;
} A;

// 基类 B
typedef struct {
    const VTableB* vptr;
    int b;
} B;

// 派生类 C(多重继承)
typedef struct {
    A a_part;  // A 部分
    B b_part;  // B 部分
    int c;
} C;

// 构造 C
C* C_new() {
    C* obj = malloc(sizeof(C));
    // 设置两个 vptr
    // obj->a_part.vptr = &C_vtable_A_part;
    // obj->b_part.vptr = &C_vtable_B_part;
    return obj;
}

// 类型转换时需要调整指针
B* C_as_B(C* obj) {
    return (B*)&obj->b_part;  // 指针偏移!
}

五、vtable 的开销与优化

5.1 空间开销

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Empty {};              // 大小: 1 byte
class WithVirtual {          // 大小: 8 bytes (64位)
    virtual void f() {}      // 只有 vptr
};

class WithData {             // 大小: 8 bytes
    int data;                // 4 bytes + 4 padding
};

class WithBoth {             // 大小: 16 bytes
    virtual void f() {}      // vptr: 8 bytes
    int data;                // 4 bytes + 4 padding
};

5.2 时间开销

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 直接调用(编译时确定地址)
void direct_call() {
    NonVirtual obj;
    obj.func();  // 1. 直接跳转到函数地址
}

// 虚函数调用(运行时查表)
void virtual_call(Base* obj) {
    obj->func();  // 1. 读取 vptr
                  // 2. 读取 vtable[index]
                  // 3. 跳转到函数地址
}

虚函数调用的汇编(x86-64):

1
2
3
4
; obj->func()
mov    rax, QWORD PTR [rdi]     ; 读取 vptr
mov    rax, QWORD PTR [rax]     ; 读取 vtable[0]
call   rax                       ; 调用函数

5.3 编译器优化

1
2
3
4
5
6
7
8
9
// devirtualization:编译器能确定类型时会优化
void optimized(Derived* d) {
    d->func();  // 编译器知道是 Derived,可能直接调用
}

// final 类/函数:阻止进一步派生/重写
class FinalClass final {
    virtual void func() final {}
};

六、RTTI 与 type_info

vtable 的第一个元素之前通常存储类型信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default;
};

class Derived : public Base {};

int main() {
    Base* b = new Derived;
    
    // RTTI 通过 vtable 获取类型信息
    const std::type_info& info = typeid(*b);
    std::cout << info.name() << "\n";  // 输出类型名称
    
    // dynamic_cast 也依赖 vtable
    Derived* d = dynamic_cast<Derived*>(b);
    if (d) {
        std::cout << "Cast succeeded\n";
    }
    
    delete b;
    return 0;
}

用 C 模拟 RTTI:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
typedef struct {
    const char* name;
    size_t size;
} TypeInfo;

typedef struct {
    const TypeInfo* type_info;  // 放在 vtable[-1] 位置
    void (*speak)(void*);
    void (*destroy)(void*);
} VTableWithRTTI;

七、完整 C 语言实现(可编译运行)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// ============================================
// C 语言实现完整的虚函数表机制
// ============================================

// 前向声明
typedef struct Animal Animal;
typedef struct Dog Dog;
typedef struct Cat Cat;

// ========== 虚函数表定义 ==========

typedef struct {
    void (*speak)(Animal* this);
    void (*eat)(Animal* this, const char* food);
    void (*destroy)(Animal* this);
    const char* type_name;
} AnimalVTable;

// ========== 基类 Animal ==========

struct Animal {
    const AnimalVTable* vptr;
    char* name;
    int age;
};

// Animal 的虚函数实现
static void Animal_speak_impl(Animal* this) {
    printf("[%s] *generic animal sound*\n", this->name);
}

static void Animal_eat_impl(Animal* this, const char* food) {
    printf("[%s] eats %s\n", this->name, food);
}

static void Animal_destroy_impl(Animal* this) {
    printf("[Animal] destroying %s\n", this->name);
    free(this->name);
    free(this);
}

// Animal 的 vtable
static const AnimalVTable Animal_vtable = {
    .speak = Animal_speak_impl,
    .eat = Animal_eat_impl,
    .destroy = Animal_destroy_impl,
    .type_name = "Animal"
};

// Animal 构造函数
Animal* Animal_create(const char* name, int age) {
    Animal* this = malloc(sizeof(Animal));
    this->vptr = &Animal_vtable;
    this->name = strdup(name);
    this->age = age;
    return this;
}

// ========== 派生类 Dog ==========

struct Dog {
    Animal base;  // 基类子对象(必须放在开头)
    char* breed;
};

// Dog 的虚函数实现
static void Dog_speak_impl(Animal* this) {
    Dog* dog = (Dog*)this;  // 向下转型
    printf("[%s the %s] WOOF WOOF! 🐕\n", dog->base.name, dog->breed);
}

static void Dog_eat_impl(Animal* this, const char* food) {
    Dog* dog = (Dog*)this;
    printf("[%s] devours %s with enthusiasm!\n", dog->base.name, food);
}

static void Dog_destroy_impl(Animal* this) {
    Dog* dog = (Dog*)this;
    printf("[Dog] destroying %s\n", dog->base.name);
    free(dog->breed);
    free(dog->base.name);
    free(dog);
}

// Dog 的 vtable
static const AnimalVTable Dog_vtable = {
    .speak = Dog_speak_impl,
    .eat = Dog_eat_impl,
    .destroy = Dog_destroy_impl,
    .type_name = "Dog"
};

// Dog 构造函数
Dog* Dog_create(const char* name, int age, const char* breed) {
    Dog* this = malloc(sizeof(Dog));
    this->base.vptr = &Dog_vtable;
    this->base.name = strdup(name);
    this->base.age = age;
    this->breed = strdup(breed);
    return this;
}

// ========== 派生类 Cat ==========

struct Cat {
    Animal base;
    int lives_remaining;
};

static void Cat_speak_impl(Animal* this) {
    Cat* cat = (Cat*)this;
    printf("[%s] Meow~ 😺 (lives: %d)\n", cat->base.name, cat->lives_remaining);
}

static void Cat_eat_impl(Animal* this, const char* food) {
    Cat* cat = (Cat*)this;
    printf("[%s] elegantly nibbles %s\n", cat->base.name, food);
}

static void Cat_destroy_impl(Animal* this) {
    Cat* cat = (Cat*)this;
    printf("[Cat] destroying %s\n", cat->base.name);
    free(cat->base.name);
    free(cat);
}

static const AnimalVTable Cat_vtable = {
    .speak = Cat_speak_impl,
    .eat = Cat_eat_impl,
    .destroy = Cat_destroy_impl,
    .type_name = "Cat"
};

Cat* Cat_create(const char* name, int age, int lives) {
    Cat* this = malloc(sizeof(Cat));
    this->base.vptr = &Cat_vtable;
    this->base.name = strdup(name);
    this->base.age = age;
    this->lives_remaining = lives;
    return this;
}

// ========== 多态接口函数 ==========

// 这些函数展示了 C++ 编译器如何实现虚函数调用
void animal_speak(Animal* animal) {
    animal->vptr->speak(animal);
}

void animal_eat(Animal* animal, const char* food) {
    animal->vptr->eat(animal, food);
}

void animal_destroy(Animal* animal) {
    animal->vptr->destroy(animal);  // 虚析构!
}

const char* animal_type(Animal* animal) {
    return animal->vptr->type_name;
}

// ========== 主程序 ==========

int main() {
    printf("╔══════════════════════════════════════════╗\n");
    printf("║   C 语言实现 C++ 虚函数表机制演示        ║\n");
    printf("╚══════════════════════════════════════════╝\n\n");

    // 创建对象(每个对象的 vptr 指向正确的 vtable)
    Dog* dog = Dog_create("Buddy", 3, "Golden Retriever");
    Cat* cat = Cat_create("Whiskers", 5, 9);
    Animal* animal = Animal_create("Generic", 10);

    // 存储在基类指针数组中
    Animal* zoo[] = {
        (Animal*)dog,
        (Animal*)cat,
        animal
    };
    int count = sizeof(zoo) / sizeof(zoo[0]);

    // 多态调用
    printf("=== 多态调用 speak() ===\n");
    for (int i = 0; i < count; i++) {
        printf("Type: %-8s | ", animal_type(zoo[i]));
        animal_speak(zoo[i]);
    }

    printf("\n=== 多态调用 eat() ===\n");
    for (int i = 0; i < count; i++) {
        animal_eat(zoo[i], "food");
    }

    // 展示 vtable 的工作原理
    printf("\n=== vtable 内部机制 ===\n");
    printf("dog->vptr = %p\n", (void*)dog->base.vptr);
    printf("cat->vptr = %p\n", (void*)cat->base.vptr);
    printf("animal->vptr = %p\n", (void*)animal->vptr);
    printf("\nvptr 不同,所以调用相同的函数会执行不同的代码!\n");

    // 虚析构
    printf("\n=== 虚析构函数 ===\n");
    for (int i = 0; i < count; i++) {
        animal_destroy(zoo[i]);
    }

    return 0;
}

八、总结

8.1 核心要点

概念 说明
vptr 每个对象都有一个隐藏的 vptr,在构造函数中初始化
vtable 每个类有一个 vtable,存储所有虚函数地址
多态原理 通过 vptr 查找 vtable,实现运行时函数绑定
开销 空间:每个对象多一个指针;时间:间接调用(2次内存访问)

8.2 等价对照

C++ 代码 C 语言等价
class Animal struct Animal + 函数指针表
virtual void speak() vtable 中的函数指针
Animal* a = new Dog() Animal* a = (Animal*)Dog_create()
a->speak() a->vptr->speak(a)
virtual ~Animal() vtable 中的 destroy 函数
override 在派生类 vtable 中替换函数指针

8.3 编译器的魔法

C++ 编译器自动完成的工作:

  1. 生成 vtable
  2. 在构造函数中设置 vptr
  3. 将虚函数调用转换为 vptr 查表
  4. 处理多重继承的 this 指针调整

参考资料

使用 Hugo 构建
主题 StackJimmy 设计