访问基类的私有虚函数 "*((int*)*(int*)(&b)+i)"

jinghuaboy 2014-03-22 03:16:24
#include <iostream>

using namespace std;

class Base
{
virtual void g()
{
cout << "Base::g" << endl;
}
virtual void f()
{
cout << "Base::f" << endl;
}
};
class Derived:public Base
{
void g()
{
cout << "Derived::g" << endl;
}
virtual void h()
{
cout << "Derived::h" << endl;
}
};

typedef void (* Fun)(void);

int main(void)
{
Derived d;
Fun pFun = NULL;
for (int i = 0; i < 3; ++i)
{
pFun = (Fun)*((int *)*(int *)(&d) + i);
pFun();
}
return 0;
}

VS2010环境下运行结果:
Derived::g
Base::f
Derived::h

结论:
1: 应该有假设“指向虚函数表vtable的虚函数表指针vt_ptr位于位于对象内存块的开始处”;
2: (Fun)*((int *)*(int *)(&d) + i): (将指针当做地址)
(&d): 获得对象d的地址addr1,此地址对应整个对象d的内存块;
(int*)(&d): 将Derived类型地址addr1强制转换为int类型地址addr2,此地址对应的内存块即为vt_ptr变量;
*(int*)(&d): 取int类型地址addr2对应内存块中的值,得int类型值val1,该值其实为虚函数表的首地址;
(int*)*(int*)(&d): 将int类型值val1强制转换为int类型地址addr3,该值即为虚函数表vtable的首地址;
((int*)*(int*)(&d)+i): 对int类型地址addr3进行算术加,得到虚函数表中元素i的地址addr_i;
*((int*)*(int*)(&d)+i): 取int类型地址addr_i对应内存块中的值的int类型值val_i,该值其实为虚函数表中元素i中存储的对应的虚函数的指针;
(Fun)*((int *)*(int *)(&d) + i): 将int类型值val_i强制转换为Fun类型地址(指针);

论证:
上述讨论中将指针看做地址,其实指针和地址应该是等效的:
int a = 0xAAAABBBB;
int *b = &a;
对以上两个定义语句,a和b都有自己的内存块,假设对应地址值分别为addr_a和addr_b。
则当执行表达式(int *)*b时,意思是将地址值addr_b对应内存块中存储的值(即为地址值addr_a)所对应的内存块中的值0xAAAABBBB强制转换为int*(即int类型指针,也即int类型地址)。

讨论:
不知这样理解是否正确?
...全文
352 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
jinghuaboy 2014-03-27
  • 打赏
  • 举报
回复
引用 6 楼 unituniverse2 的回复:
“不同编译器对虚函数表的支持也是有差别的也是知道的” 有些编译器对虚函数的实现中根本没有虚表
虚函数实现跟编译器有关。最近在看一些面试题,各种奇葩问题,比较疑惑。
unituniverse2 2014-03-22
  • 打赏
  • 举报
回复
“不同编译器对虚函数表的支持也是有差别的也是知道的” 有些编译器对虚函数的实现中根本没有虚表
Walle_Oyq 2014-03-22
  • 打赏
  • 举报
回复
个人感觉是奇技淫巧,实际上编程基本上不会用到,当然你要用也没人说。
jinghuaboy 2014-03-22
  • 打赏
  • 举报
回复
引用 1 楼 taodm 的回复:
等你多试几种编译器,多试几种继承模式后,再说吧。 讨论这东西就是浪费生命的。
我只是想问在本问题设定的条件下,对结论(2)中 “(Fun)*((int *)*(int *)(&d) + i)”的理解是否合理、正确。 其他几种继承模式是知道的,不同编译器对虚函数表的支持也是有差别的也是知道的。
lm_whales 2014-03-22
  • 打赏
  • 举报
回复
引用 1 楼 taodm 的回复:
等你多试几种编译器,多试几种继承模式后,再说吧。 讨论这东西就是浪费生命的。
++
jinghuaboy 2014-03-22
  • 打赏
  • 举报
回复
我只是想问在本问题设定的条件下,对结论(2)中 “(Fun)*((int *)*(int *)(&d) + i)”的理解是否合理、正确。 其他几种继承模式是知道的,不同编译器对虚函数表的支持也是有差别的也是知道的。
taodm 2014-03-22
  • 打赏
  • 举报
回复
等你多试几种编译器,多试几种继承模式后,再说吧。 讨论这东西就是浪费生命的。

65,208

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧