对于含有虚函数的类(基类或者自身(自身非纯虚函数))的对象,都拥有一个指向虚函数表的指针(占一个指针大小的内存,在类成员变量之前,相当于第一个成员变量。多重继承的时候,几个基类就几个指针,就几个虚函数表)。
每个类的虚函数表确定了各个方法指向那个实现,只有虚函数才会加入虚函数表,非虚函数不会加入其中。如果基类中是虚函数,派生类中就是虚函数。以此处为例。
类 Girl的对象的虚函数表 含有 showAge和showMaxim的指向,用来确定调用那个函数,所以无论是基类指针还是派生类的指针指向派生类对象,调用都不会出错。
定义几个简单的类
1: #include <iostream>
2:
3: using namespace std;
4:
5:
6: class A
7: {
8: public:
9: virtual void show() = 0
10: {
11: cout << "A show" << endl;
12: }
13: void showR()
14: {
15: cout << "A show Not virtual" << endl;
16: }
17: };
18:
19: class B :public A
20: {
21: public:
22: virtual void show()
23: {
24: cout << "B show" << endl;
25: }
26: void showR()
27: {
28: cout << "B show Not virtual" << endl;
29: }
30: };
31:
32: class C :public A
33: {
34: public:
35: virtual void show()
36: {
37: cout << "C show" << endl;
38: }
39:
40: };
41:
42:
43: class D :public B, public C
44: {
45: };
46:
main函数
1: int main()
2: {
3: A *pB = new B;
4: A *pC = new C;
5:
6: //不能用A指针指向D对象,error:基类不明确
7: B *pDB = new D;
8: C *pDC = new D;
9:
10: pB->show(); //输出:B show
11: pC->show(); //输出:C show
12: pDB->show(); //输出:B show
13: pDC->show(); //输出:C show
14:
15: //A中的showR并未加入虚函数表,所以此处类A的指针调用的是A中的实现
16: pB->showR(); //输出:A show Not virtual
17: pC->showR(); //输出:A show Not virtual
18: //B有重写showR,B的指针调用B的showR
19: pDB->showR(); //输出:B show Not virtual
20: //C中没有写showR,C的指针会调用其基类的实现
21: pDC->showR(); //输出:A show Not virtual
22:
23: cin.get();
24:
25:
26: return 0;
27: }
28:
简单分析下,这是在VS2013下调试的,没有在G++等编译器上测试
以下为没有实现D中的show的时候。pB指向的B类对象具有两个虚函数表指针(void**类型),两个指针指向同一个地址。也就是是其实这里只有一个虚函数表,这个表中含有一个指针(void*),指向B::show(void)这个函数。
下面是pDB和pDC指针指向的对象(都是D类对象)的虚函数表。可以看到两个对象的虚函数表是不一样的,虽然都是D的对象。两者在前两个虚函数表是一样的,只是在最后一个有不同。前两个虚函数表是按照继承顺序,分别来自基类B和基类C(继承B中来来自A中的,B中有一个是属于B的__vfptr,一个继承自A的__vfptr,这里继承的是B中来自A的)。最后一个是D本身的虚函数表(还是来自A的,A是纯抽象基类),当是B类指针指向的时候,其地址是B中show实现的地址。当是C类指针指向的时候,其地址是C中show实现的地址。(本处图片是在D中尚未对虚函数实现的情况下)
从下面图中可以看出来,pDB指向对象继承了B中来自A的__vfptr,其和pB指向对象中继承自A的虚函数指针指向的虚函数表是同一个。
D中实现show后,可以从下面图中看出,六个虚函数表中都是D::show(void),但是还是有不一样的的。在pDB指向的对象中其继承自C的虚函数表指针指向的虚函数表中的函数是D::show(void)`adjustor{4}`,其自身的虚函数表和继承自B的虚函数表,都是D::show(void)。而pDC指向的对象,继承自C的和自身的虚函数表都是D::show(void)`adjustor{4}`,继承自B的虚函数表是D::show(void)。 (
在类A中添加私有虚函数P(virtual int P(void))后,被添加到虚函数表。P仅仅在A中给出了实现,在B和C中没有实现。可以看到所有的虚函数表中的第一个元素都是指向同一个地址。
在类B中实现虚函数P后,可以看到pDB指向对象中的继承自B的虚函数表和自身继承A的虚函数表是一样的。继承自C的虚函数表是不一样的。
1.cpp C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/INCLUDE/xlocale(337) : warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc class Human size(8): +--- 0 | {vfptr} 4 | age +--- Human::$vftable@: | &Human_meta | 0 0 | &Human::showAge Human::showAge this adjustor: 0 class ?$is_error_code_enum@PAVHuman@@ size(1): +--- | +--- (base class ?$integral_constant@_N$0A@) | +--- +--- Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:1.exe 1.obj |
1.cpp C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/INCLUDE/xlocale(337) : warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc class Female size(4): +--- 0 | {vfptr} +--- Female::$vftable@: | &Female_meta | 0 0 | &Female::showMaxim Female::showMaxim this adjustor: 0 class ?$is_error_code_enum@PAVFemale@@ size(1): +--- | +--- (base class ?$integral_constant@_N$0A@) | +--- +--- Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:1.exe 1.obj |
1.cpp C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/INCLUDE/xlocale(337) : warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc class Women size(16): +--- | +--- (base class Human) 0 | | {vfptr} 4 | | age | +--- | +--- (base class Female) 8 | | {vfptr} | +--- 12 | charm +--- Women::$vftable@Human@: | &Women_meta | 0 0 | &Women::showAge Women::$vftable@Female@: | -8 0 | &Women::showMaxim Women::showAge this adjustor: 0 Women::showMaxim this adjustor: 8 //在源代码中注释掉Women中showMaxim实现后,将没有此句 class ?$is_error_code_enum@PAVWomen@@ size(1): +--- | +--- (base class ?$integral_constant@_N$0A@) | +--- +--- Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:1.exe 1.obj |
1.cpp C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/INCLUDE/xlocale(337) : warning C4530: 使用了 C++ 异常处理程序,但未启用展开语义。请指定 /EHsc class Girl size(16): +--- | +--- (base class Women) | | +--- (base class Human) 0 | | | {vfptr} 4 | | | age | | +--- | | +--- (base class Female) 8 | | | {vfptr} | | +--- 12 | | charm | +--- +--- Girl::$vftable@Human@: | &Girl_meta | 0 0 | &Girl::showAge Girl::$vftable@Female@: | -8 0 | &Girl::showMaxim Girl::showAge this adjustor: 0 Girl::showMaxim this adjustor: 8 class ?$is_error_code_enum@PAVGirl@@ size(1): +--- | +--- (base class ?$integral_constant@_N$0A@) | +--- +--- Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:1.exe 1.obj |
from: http://www.th7.cn/Program/cp/201411/320604.shtml