C++虚函数和虚函数表

时间:2022-12-22 03:29:07

前导

在上面的博文中描述了基类中存在虚函数时,基类和派生类中虚函数表的结构。

在派生类也定义了虚函数时,函数表又是怎样的结构呢?

先看下面的示例代码:

 1 #include <iostream>
2
3 using namespace std;
4
5 class A
6 {
7 public:
8 virtual void funcA(){ cout<<"A"<<endl; }
9 };
10
11 class B
12 {
13 public:
14 virtual void funcB(){ cout<<"B"<<endl; }
15 };
16
17 class C : public A, public B
18 {
19 public:
20 virtual void funcC(){ cout<<"C"<<endl; }
21 };
22
23 int main()
24 {
25 C c;
26 cin.get();
27 }

class A 和 class B 都有一个虚函数,然后 class C 继承 A 和 B。在VS2010中,查看变量:

C++虚函数和虚函数表

如图所示,局部变量中只显示了从 A 和 B 继承来的虚函数表地址。那么 C 自己的虚函数呢?

首先查看 A 虚函数表地址:

 C++虚函数和虚函数表

可以看到,虚函数表中的前4个字节就是 A 中虚函数的地址(红色框)。同时后面又紧跟着4个有内容的字节,然后才是表示虚函数表结束的4个0。

可以猜测,这应该就是 C 的虚函数地址。再来看一下 B 的虚函数表:

C++虚函数和虚函数表

可以看到,虚函数表中只有 B 的虚函数这一个地址。为了证实上面的猜测,将函数指针从 A::funcA 向后递增一次,应该就是对 C::funC的调用:

int main()
{
typedef
void(*pfun)();

C c;
auto p
= &c;

auto funcA
= (pfun)**((int**)p);
funcA();
// 调用 A::funcA

auto funcC
= (pfun)*(*((int**)p) + 1);
funcC();
// 调用 C::funcC

cin.
get();
}

输出结果:C++虚函数和虚函数表 证实了我们的猜测。

 

如果在增加一个 class D 继承 C 呢?

class D : public C
{
virtual void funcD() {}
};

int main()
{
D d;

cin.
get();
}

变量:

C++虚函数和虚函数表

和 C 中展示的一样,只有两个虚函数表。

内存:

C++虚函数和虚函数表

可以看到,在 A::funcA 后还有两个地址,可以推测就是 C::funcC 和 D::funcD 的地址了。

 

总结:

1、在多继承中,派生类的虚函数表的个数由它所继承的“顶层的”基类的个数决定:有多少个这样的基类,就有多少个虚函数表。

2、派生类自己的虚函数被追加到第一个虚函数表的后面。

例如下面的继承:

C++虚函数和虚函数表

假设每个类 X 都有一个 funcX 虚函数,那么G中虚函数和虚函数表如下:

C++虚函数和虚函数表