首页 > 编程知识 正文

C 中的虚函数表和虚函数在内存中的位置,虚函数表指针的位置

时间:2023-05-04 02:26:05 阅读:275116 作者:1740

 目录

结论


       今天在看别人面经的时候发现了这个问题,一时间发现自己也说不清楚,还想当然的以为“虚函数表既然是类对象公有的,那么应该在静态存储区”,想当然终究只是想当然,经过试验得知,这种想法是错误的。

       由于不同的编译器在虚函数表上的实现可能不同,下面以g++来进行分析。

       先创建一个有虚函数的类A,如下所示:

class A{public:A(){};~A(){};virtual void vfun(){cout<<"vfun called!"<<endl;}};

       既然要知道虚函数表的位置,那么自然就需要找到虚函数表的地址。我们知道,对于类A这种简单的类,其对象内存布局的最开始四个字节就是一个虚函数表指针(32位编译器),而这个指针变量的值自然就是虚函数表的地址了,因此,第一步就是获取这个虚函数表指针来找到虚函数表的地址:(可参考)

A *a = new A();

long vbaddr=*(int *)a;   //虚函数表地址

       由于只有一个虚函数,所以虚函数表的前4个字节肯定就是vfun的函数地址,因此根据虚函数表的地址还可以得到虚函数vfun的地址:

long vfaddr= *(int *)vbaddr;  //虚函数A::vfun的地址

       然后还可以根据vfun的地址来调用这个函数:

((void(*)(void))vfaddr)();  //根据得到的地址来调用虚函数 

      如果通过vfaddr来调用函数是成功的,那么就说明前面虚函数表的地址都是正确的。

      得出以下程序: 

#include <iostream>using namespace std;class A{public:A(){};~A(){};virtual void vfun(){cout<<"vfun called!"<<endl;}};int main(){A *a = new A();long vbaddr=*(int *)a; //虚函数表地址long vfaddr= *(int *)vbaddr; //虚函数vfun地址cout<<"addr of vb : "<<vbaddr<<endl;cout<<"addr of vfun : "<<vfaddr<<endl;((void(*)(void))vfaddr)(); //根据虚函数地址调用虚函数delete a;return 0;}

      用g++进行编译生成可执行文件,然后运行:

      从运行结果可以看到,虚函数表的地址是0x400be0(4197344),虚函数vfun的地址为0x400aea(4197098),并且根据虚函数vfun的地址成功调用了虚函数,打印了“vfun called”,这说明获取的0x400be0确实是虚函数表的地址。

      接下来就看看0x400be0这个地址在可执行文件内存中的哪个段。

      用objdump -s 可以解析ELF格式的可执行文件中的分段信息:

       每个分段的内容用Contents of section .xxx来分隔,xxx表示下面的内容属于哪个段。在这些段的内容中,每一行的第一个16进制数表示的是相应的段中的一个地址,以400238 2f6c6962 3634.......这一行为例,首地址为0x400238,那么从0x400238到下一行首地址0x400248之间的16个字节中存放的数据就是0x2f 0x6c 0x69 0x62.......

       回到虚函数表的地址上来,前面说了,虚函数表的地址为0x400be0,现在来看看这个地址是属于哪个段:

      可以看到,0x400be0这个地址,刚好就在.rodata这个段中,这个段就是C++中的常量区,并且还可以发现,从这个地址开始取4个字节“ea0a4000”,由于是小端模式,因此取出来的4字节数为0x400aea,是不是很眼熟呢?没错,这个地址就是前面求得的虚函数vfun的地址

      同理,根据虚函数vfun的0x400aea地址,还可以找到虚函数vfun的位置:

      可以看到,虚函数vfun位于.text代码段,也就是C++中的代码区。

结论

      综上所述: C++中虚函数表位于只读数据段(.rodata),也就是C++内存模型中的常量区;而虚函数则位于代码段(.text),也就是C++内存模型中的代码区。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。