这篇文章主要介绍“C++虚函数表存储位置在哪”,在日常操作中,相信很多人在C++虚函数表存储位置在哪问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++虚函数表存储位置在哪”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
先说结论:虚函数表存储在只读数据段(.rodata
)、虚函数存储在代码段(.text
)、虚表指针的存储的位置与对象存储的位置相同,可能在栈、也可能在堆或数据段等。
环境:gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
验证代码:
#include <iostream> using namespace std; class Q { public: virtual void Test() { cout << "Test" << endl; } }; class Qgw : public Q { public: virtual void Test() { cout << "Test Position" << endl; } }; int main() { Q* q = new Qgw; q->Test(); return 0; }
并不采用打印地址的方式,因为打印出的地址与反汇编得到的地址不同,无法直接得出结果。
首先编译代码:g++ -o test test.cc -O0 -m32
,以 32 位方式编译。
然后将符号表输出到文件:objdump -tC test > test.txt
。
打开 test.txt 可以找到以下内容:
000012fc w F .text 00000044 Qgw::Test()
0000201c w O .rodata 00000005 typeinfo name for Qgw
00003ea8 w O .data.rel.ro 0000000c typeinfo for Qgw
00003e90 w O .data.rel.ro 0000000c vtable for Qgw
第一行比较清晰,说明 Qgw::Test()
存储在 .text
段,也就说明虚函数和普通函数一样,都存储在代码段。
下面几行又是什么东西呢?
根据《深度探索 C++ 对象模型》的 C++ 对象模型可知,typeinfo 是存储在虚函数表中,用来获取对象类型信息的。最下面的 .data.rel.ro
是只读数据段的重定位段,在链接时重定位。由此,可以推出虚函数表是存储在只读数据段的。
也可以采用打印地址的方式,与已知的一些段地址比较,看虚函数表地址和哪个段地址更接近。
环境:gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04)
验证代码:
#include <iostream> using namespace std; class Qgw { public: virtual void Test() { cout << "Test Position" << endl; } }; void Func() { cout << "func" << endl; } int n = 10; int main() { Qgw* q = new Qgw; q->Test(); const char* arr = "qgw"; cout << "text: " << (void*)Func << endl; cout << ".rodata: " << (void*)arr << endl; cout << "虚函数表: " << *(void**)q << endl; cout << ".data: " << &n << endl; return 0; }
函数的地址在上文已经验证了,全局变量和常量字符串的位置,《深入理解计算机系统(第三版)》中说明如下:
.rodata
:只读数据 比如 printf 语句中的格式串(%d\n
) .data
:已初始化的全局和静态 C 变量
它们的布局如下图:
编译运行上述代码,得到以下结果:
可以看到虚函数表的位置在数据段和只读数据段位置之间,我们是无法手动修改虚函数表的,因此存储在只读数据段是比较合理的。
到此,关于“C++虚函数表存储位置在哪”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。