您的位置:首页 > 编程语言 > C语言/C++

C++ 多态虚函数表(VS2013)

2016-03-19 23:25 471 查看
对于含有虚函数的类(基类或者自身(自身非纯虚函数))的对象,都拥有一个指向虚函数表的指针(占一个指针大小的内存,在类成员变量之前,相当于第一个成员变量。多重继承的时候,几个基类就几个指针,就几个虚函数表)。

每个类的虚函数表确定了各个方法指向那个实现,只有虚函数才会加入虚函数表,非虚函数不会加入其中。如果基类中是虚函数,派生类中就是虚函数。以此处为例。

类 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: