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

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

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

类 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)这个函数。

image

下面是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中尚未对虚函数实现的情况下)

image

从下面图中可以看出来,pDB指向对象继承了B中来自A的__vfptr,其和pB指向对象中继承自A的虚函数指针指向的虚函数表是同一个。

image

 

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)。 (

 

image

在类A中添加私有虚函数P(virtual int P(void))后,被添加到虚函数表。P仅仅在A中给出了实现,在B和C中没有实现。可以看到所有的虚函数表中的第一个元素都是指向同一个地址。

 

image

 

 

 

 

 

 

 

 

 

在类B中实现虚函数P后,可以看到pDB指向对象中的继承自B的虚函数表和自身继承A的虚函数表是一样的。继承自C的虚函数表是不一样的。

image

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值