虚函数的机制

虚函数在类中的体现

对象的多态性需要通过虚表和虚表指针来完成,虚表指针被定义在对象首地址的前4字节处,因此虚函数必须作为成员函数使用。 
由于非成员函数没有 this 指针,因此无法获得虚表指针,进而无法获取虚表,也就无法访问虚函数。

子类对虚函数进行了重写,所以如果是子类的指针,是访问不到父类的成员函数的。而父类的指针可以访问到子类的成员函数。

值得注意的是,虽然虚表是共享的,但是虚表指针并不是,类的每一个对象有一个属于它自己的虚表指针。

编译环境:VS2012

  • 类中只有普通成员函数:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

类大小图1

  • 类中含有虚函数:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

类大小图2

由此可见,有虚函数的多了4个字节,这4个字节就是分给虚函数指针的.


虚函数表的存储机制

一般继承(无虚函数覆盖)

C++代码:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">#include <iostream></span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">using</span> namespace std;
class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_b(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_c(){}
};
class CClassB : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_e</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_f(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_g(){}
};
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main()
{
    CClassA objA;
    CClassB objB;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>

反汇编代码:

  • CClassB 的虚函数表
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassB@@6B@ DD FLAT:??_</span>R4CClassB@@6B@      ; CClassB::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_e@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_f@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_g@CClassB@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
  • CClassA 的虚函数表
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassA@@6B@ DD FLAT:??_</span>R4CClassA@@6B@      ; CClassA::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassA@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

可以看到,虚函数表存放在常量段里(模块的数据段通常存放该模块的全局数据和静态数据,这样我们可以把虚表看作是模块的全局数据或者静态数据),并且 CClassB 继承 CClassA 后,虚函数表中的函数排列顺序为先基类再子类。

也可以在内存中证明排列顺序,如图: 
objB 的前三个是 objA 的三个函数

objB-objA

可得objB 的虚函数结构为: 
objB 的虚函数结构


一般继承(有虚函数覆盖)

C++代码:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_b(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_c(){}
};
class CClassB : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}   <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//覆盖基类的fun_a</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_f(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_g(){}
};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

汇编中的虚函数表:

  • CClassB: (这里 fun_a 已经不再是 CClassA 的了)
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassB@@6B@ DD FLAT:??_</span>R4CClassB@@6B@      ; CClassB::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_f@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_g@CClassB@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>
  • CClassA:
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassA@@6B@ DD FLAT:??_</span>R4CClassA@@6B@      ; CClassA::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassA@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

在内存中的情况: 
第一个函数已经不同,说明基类中的被覆盖

这里写图片描述

objB 的虚函数结构为:

这里写图片描述


多重继承(无虚函数覆盖)

C++代码:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_b(){}
};
class CClassB 
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_c</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_d(){}
};
class CClassC : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassA, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassB
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    /*<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_c(){}*/
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_e(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_f(){}
};
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main()
{
    CClassA objA;
    CClassB objB;
    CClassC objC;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>

反汇编各个类的虚函数表:

  • CLassC (有两个虚函数表): 
    可以看到 C 本身 的虚函数被接在第一个继承类 CClassA 的后面
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassC@@6BCClassB@@@ DD FLAT:??_</span>R4CClassC@@6BCClassB@@@ ; CClassC::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_d@CClassB@@UAEXXZ</span>
CONST   ENDS
CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassC@@6BCClassA@@@ DD FLAT:??_</span>R4CClassC@@6BCClassA@@@ ; CClassC::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_e@CClassC@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_f@CClassC@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
  • CClassB :
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassB@@6B@ DD FLAT:??_</span>R4CClassB@@6B@      ; CClassB::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_d@CClassB@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
  • CClassA :
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassA@@6B@ DD FLAT:??_</span>R4CClassA@@6B@      ; CClassA::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

在内存中查看: 
objC 的总体情况(两个虚函数指针 vfptr):

这里写图片描述

  • objC 的内存:

这里写图片描述

第一个虚函数表指针 0036CD58H:

这里写图片描述

其中4个地址的内容分别是:(这里也可以看出 C 的虚函数跟在 A 的后面)

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

第二个虚函数表指针 0036CD74H:

这里写图片描述

其中2个地址的内容分别是:(这里就是第二个继承类的虚函数)

这里写图片描述

这里写图片描述

SO , CClassC 的虚表结构:

这里写图片描述


多重继承(有虚函数覆盖)

C++代码:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">class CClassA
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_b(){}
};
class CClassB 
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_c</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_d(){}
};
class CClassC : <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassA, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> CClassB
{
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span>:
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">fun_a</span>(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_c(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_e(){}
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">virtual</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> fun_f(){}
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> main()
{
    CClassA objA;
    CClassB objB;
    CClassC objC;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>

反汇编虚函数表:

  • CClassC:
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassC@@6BCClassB@@@ DD FLAT:??_</span>R4CClassC@@6BCClassB@@@ ; CClassC::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassC@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_d@CClassB@@UAEXXZ</span>
CONST   ENDS

CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassC@@6BCClassA@@@ DD FLAT:??_</span>R4CClassC@@6BCClassA@@@ ; CClassC::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassC@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_e@CClassC@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_f@CClassC@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>
  • CClassB:
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassB@@6B@ DD FLAT:??_</span>R4CClassB@@6B@      ; CClassB::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_c@CClassB@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_d@CClassB@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
  • CClassA:
<code class="hljs asciidoc has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">CONST   SEGMENT
??<span class="hljs-emphasis" style="box-sizing: border-box;">_7CClassA@@6B@ DD FLAT:??_</span>R4CClassA@@6B@      ; CClassA::<span class="hljs-smartquote" style="box-sizing: border-box;">`vftable'</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_a@CClassA@@UAEXXZ</span>
<span class="hljs-code" style="box-sizing: border-box;">    DD  FLAT:?fun_b@CClassA@@UAEXXZ</span>
CONST   ENDS</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

在内存中查看: 
objC 的内存:

这里写图片描述

第一个虚表:

这里写图片描述

对应的函数:

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

第二个虚表内容:

这里写图片描述

对应的函数:

这里写图片描述

这里写图片描述

SO , CClassC 的虚表结构:

这里写图片描述

值得注意的是,如果基类中有数据成员被继承,那么 CClassC 的对象的模型应该是这样的:

这里写图片描述

转载自:http://blog.youkuaiyun.com/hwithk/article/details/47976571

<think>我们正在讨论C++中的虚函数机制,用户要求通过实例来了解。根据引用[1][2][3],虚函数的实现依赖于虚函数表(vtable)和虚表指针(vptr)。下面我将通过一个具体的实例来详细解释虚函数机制。 ### 1. 虚函数的基本实现机制 当一个类包含至少一个虚函数时,编译器会为该类生成一个**虚函数表(vtable)**,并在每个对象中添加一个隐藏的**虚表指针(vptr)** 指向该表[^2]。虚函数表是一个函数指针数组,按顺序存储该类所有虚函数的地址。例如: ```cpp class Animal { public: virtual void speak() { cout << "Animal speaks!" << endl; } virtual void sleep() { cout << "Animal sleeps!" << endl; } }; ``` - 编译器会为`Animal`类创建虚函数表`Animal_vtable`: ```plaintext [0]: Animal::speak 的地址 [1]: Animal::sleep 的地址 ``` - 当创建`Animal`对象时,其内存布局如下: ```plaintext +-----------+ | vptr | --> 指向Animal_vtable | ...其他成员... | +-----------+ ``` ### 2. 派生类重写虚函数 当派生类重写基类的虚函数时,虚函数表会被更新: ```cpp class Cat : public Animal { public: void speak() override { cout << "Meow!" << endl; } // 重写speak() void sleep() override { cout << "Cat sleeps!" << endl; } // 重写sleep() }; ``` - `Cat`类的虚函数表变为: ```plaintext [0]: Cat::speak 的地址 // 替换基类函数 [1]: Cat::sleep 的地址 // 替换基类函数 ``` - `Cat`对象的内存布局: ```plaintext +-----------+ | vptr | --> 指向Cat_vtable(而非Animal_vtable) | ...其他成员... | +-----------+ ``` ### 3. 多态调用的底层过程 通过基类指针调用虚函数时,实际执行的是派生类的实现: ```cpp Animal* animal = new Cat(); animal->speak(); // 输出 "Meow!" ``` 执行过程: 1. 通过`animal`指针找到对象的`vptr`(位于对象起始位置)[^3]。 2. 通过`vptr`找到虚函数表`Cat_vtable`。 3. 在虚函数表中索引`speak`的位置(通常是索引0)。 4. 调用该位置存储的函数地址(即`Cat::speak`)。 ### 4. 动态绑定与静态绑定的区别 - **静态绑定**:在编译期确定函数调用地址(如非虚函数)。 ```cpp animal->Animal::speak(); // 强制静态绑定,输出"Animal speaks!" ``` - **动态绑定**:在运行时通过虚函数表查找函数地址(如虚函数调用)[^4]。 ### 5. 多重继承下的虚函数表 引用[5]说明,多重继承时派生类会有多个虚函数表: ```cpp class Base1 { public: virtual void f1() {} }; class Base2 { public: virtual void f2() {} }; class Derived : public Base1, public Base2 { public: void f1() override {} // 重写Base1::f1 virtual void f3() {} // 新的虚函数 }; ``` - `Derived`对象包含两个虚表指针: - `vptr1`指向`Base1`的虚表(内容为`Derived::f1`的地址) - `vptr2`指向`Base2`的虚表(内容为`Base2::f2`的地址) - 新增的虚函数`f3`会附加到第一个基类的虚函数表中(即`Base1`的虚表末尾)[^5]。 ### 总结 虚函数机制的核心是通过**虚函数表**和**虚表指针**实现动态绑定: 1. 每个包含虚函数的类拥有唯一的虚函数表。 2. 对象通过虚表指针访问实际应调用的函数。 3. 重写虚函数时,派生类虚函数表会覆盖基类函数地址。 4. 多重继承导致多个虚表共存。 §§相关问题§§ 1. 虚函数表在内存中的存储位置是哪里? 2. 虚函数调用相比普通函数调用有哪些性能开销? 3. 如何避免滥用虚函数导致的设计问题? </think>### C++虚函数机制实例详解 #### 1. **核心组件:虚函数表(vtable)与虚表指针(vptr)** 当类包含虚函数时,编译器自动生成虚函数表: - **虚函数表(vtable)**:存储类中所有虚函数的地址指针数组 - **虚表指针(vptr)**:每个对象内部的隐藏指针,指向其类的vtable ```cpp class Animal { public: virtual void speak() { cout << "Animal sound!" << endl; } // 虚函数[^2] virtual void eat() { cout << "Animal eating!" << endl; } // 虚函数 }; // 内存布局示意 Animal animal; /* +------------+ | vptr | --> 指向Animal的vtable | ...成员变量... | +------------+ Animal类的vtable: [0]: Animal::speak地址 [1]: Animal::eat地址 */ ``` #### 2. **继承时的动态绑定** 派生类重写虚函数时,vtable内容更新: ```cpp class Cat : public Animal { public: void speak() override { cout << "Meow!" << endl; } // 覆盖基类虚函数[^3] }; // 使用示例 Animal* animal = new Cat(); animal->speak(); // 输出"Meow!",动态绑定到Cat的实现 /* Cat对象的vtable: [0]: Cat::speak地址 // 替换基类函数指针 [1]: Animal::eat地址 // 继承基类实现 */ ``` #### 3. **多重继承的vtable结构** 引用[5]说明的多重继承场景: ```cpp class A { virtual void f1(); }; class B { virtual void f2(); }; class C : public A, public B { void f1() override; // 覆盖A::f1 virtual void f3(); // 新增虚函数 }; /* C类实例的vtable布局: +-------------+ +-------------+ | A的vtable | | B的vtable | |-------------| |-------------| | C::f1地址 | | B::f2地址 | // 被覆盖的函数 | C::f3地址 | +-------------+ +-------------+ */ ``` #### 4. **动态绑定原理剖析** 通过基类指针调用时的底层过程: 1. 通过对象找到vptr (`mov eax, [ecx]`) 2. 在vtable中定位函数偏移量 3. 跳转到实际函数地址 (`call [eax+offset]`) ```cpp Instrument* ins = new Wind(); ins->play(); // 动态绑定过程: /* 1. 获取ins对象首地址(即vptr地址) 2. 读取vptr指向的vtable 3. 在vtable中定位play()的槽位 4. 调用Wind::play()而非Instrument::play()[^4] */ ``` #### 5. **构造函数与虚函数限制** - **构造函数不能是虚函数**:构造时vptr尚未初始化[^1] - **析构函数应为虚函数**:确保正确调用派生类析构 ```cpp class Base { public: Base() { // 此时vptr指向Base的vtable // 调用虚函数将执行Base的实现 } virtual ~Base() {} // 虚析构确保多态删除安全 }; ``` ### 关键结论 1. **动态绑定核心**:通过vptr和vtable实现运行时多态[^2][^3] 2. **性能开销**:每次虚函数调用增加一次指针寻址(约1-2时钟周期) 3. **内存开销**:每个对象增加一个vptr指针(通常4/8字节) 4. **设计意义**:实现"接口与实现分离"的OOP核心理念[^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值