Jiahonzheng's Blog

C++ 虚函数的实现

字数统计: 367阅读时长: 1 min
2018/04/25 Share

多态的原理

通常,编译器处理虚函数的原理是:给每个类实例添加一个隐藏成员,这个隐藏成员保存了一个指向函数指针数组的指针,该数组称为虚函数表,我们用 vtable 指代它,我们用 vptr 指代指向该数组的指针。

通常, vptr 位于类实例内存的最前面的位置,由于 vtable 为存储函数指针的数组,故我们可以通过指针操作获得 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
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
#include <iostream>

// 定义类时,虚函数的声明顺序,决定了 vtable 内函数指针的顺序

class Base {
public:
Base() = default;
virtual void fun1() { std::cout << "Base::fun1()" << std::endl; }
virtual void fun2() { std::cout << "Base::fun2()" << std::endl; }
virtual ~Base() = default;
};

class Derived : public Base {
public:
Derived() = default;
virtual void fun1() { std::cout << "Derived::fun1()" << std::endl; }
virtual void fun2() { std::cout << "Derived::fun2()" << std::endl; }
virtual ~Derived() = default;
};

typedef void (*fun)(); // 函数指针

int main() {
Base* b = nullptr;
size_t* vptr = nullptr; // vptr 位于类实例内存的头部
size_t* vtable = nullptr; // vtable 即为函数指针数组
fun pfun = nullptr;

b = new Base();
vptr = (size_t*)b; // 获取 vptr 地址
vtable = (size_t*)*vptr; // 获取 vtable 地址

pfun = (fun)*vtable; // 获取指针数组的第一元素
pfun();

pfun = (fun) * (vtable + 1); // 获取指针数组的第二元素
pfun();

delete b;

b = new Derived();
vptr = (size_t*)b;
vtable = (size_t*)*vptr;

pfun = (fun)*vtable;
pfun();

pfun = (fun) * (vtable + 1);
pfun();

delete b;

return 0;
}
CATALOG
  1. 1. 多态的原理
  2. 2. 代码示例