【虚函数、虚拟指针、虚表指针】解析多重继承时,虚表的分布
来源:互联网 发布:免费的大数据分析平台 编辑:程序博客网 时间:2024/06/06 13:18
#include<iostream>using namespace std;//抽象基类:动物类class CAnimal{public: virtual void EatFood(string strSomething) = 0; virtual void Drink(string strSomething) = 0;};//CAnimal的派生类:CMammalclass CMammal : public CAnimal{public: virtual void EatFood(string strSomething) { cout << "CMammal::EatFood()" << endl; } virtual void Drink(string strSomething) { cout << "CMammal::Drink()" << endl; }};//CAnimal的继承类:CAfricaAnimal非洲动物class CAfricaAnimal : public CAnimal{public: virtual void EatFood(string strSomething) { cout << "CAfricaAnimal::EatFood()" << endl; } virtual void Drink(string strSomething) { cout << "CAfricaAnimal::Drink()" << endl; }};//同时继承自CMammal,CAfricaAnimal:CLion狮子类class CLion : public CMammal, public CAfricaAnimal{public: virtual void RunCrazily() { cout << "CLion::RunCrazily()" << endl; }};
现有以下
int main(){ CLion sinba; return 0;}
通过在return 0;语句前添加一个断点,查看sinba的值可以得到如下结果:
由此我们可以得出如下结论:
在多重继承中,会根据含有虚函数的基类确定有多少张虚表。有多少个含有虚函数的基类,就会有多少张虚表每个基类的虚表是按照在继承列表中的声明顺序而存放的。从上面的调试窗口可以看到,Clion中有两张虚表:首先是Cmammal的,然后是CafricaAnimal的。
在Clion中定义了一个Clion自己的虚函数RunCrazily,可是从调试窗口中并没有看到RunCrazily。那么这张表到底存放在哪里呢?通过网上查阅资料,得知这张表其实是存放在第一张虚表中的。一下是测试代码:
CLion sinba;typedef void (*FUN)(); //函数指针FUN run_crazily = (FUN)(*((int*)*(int*)(&sinba)+2)); run_crazily();//CLion::RunCrazily()
关于上面复杂指针转换的分析: (int*)(&sinba)得到的是一个指向第一张虚表地址的指针,该虚表中存放的是虚函数的函数指针,每项占4字节。对该地址取内容:*(int*)(&sinba) 可以得到第一张虚表的首地址,但应该将该值转换成int*,使得每次指针+1操作都内存向前移动4字节,即虚表中一个元素的长度:(int*)*(int*)(&sinba)。因为虚表中元素占4字节,现在把这个指针向前移动两个元素: (int*)*(int*)(&sinba)+2,得到表中第三项的地址,对该项取内容,得到函数的入口地址,即CLion::RunCrazily()的入口地址:*((int*)*(int*)(&sinba)+2). 得到这个值以后还不能直接调用,应该将该函数入口点转换成相应的函数原型(FUN)(*((int*)*(int*)(&sinba)+2))。现在可以调用了如果要得到第二张虚表中的某项函数可以按照上面分析的方法调用到:(int*)(&sinba):一个指向第一张虚表地址的指针(这里必须转换成int*,方便在指针移动的时候可以向前移动4字节,也就是一个虚表指针的长度)(int*)(&sinba)+1:一个指向第二张虚表地址的指针*((int*)(&sinba)+1):对上面的地址取内容,得到第二张虚表的首地址(int*)*((int*)(&sinba)+1)+1:第二张虚表中第二项的地址(这里也必须转换成int*再+1,原因同上面的)*((int*)*((int*)(&sinba)+1)+1):对上面的地址取内容,得到第二张虚表中第二项的入口地址(FUN)(*((int*)*((int*)(&sinba)+1)+1)):对上面的地址强制转换成相应原型的函数指针
1 0
- 【虚函数、虚拟指针、虚表指针】解析多重继承时,虚表的分布
- 多重继承、虚函数、this指针偏移
- c++多重继承下虚函数的this指针问题
- 多重继承、虚继承下的this指针偏移
- 虚函数表指针和虚继承
- C++虚继承和多重继承时的指针类型转换
- 多重继承下的虚函数表
- 多重继承及虚继承中对象内存的分布
- 多重继承及虚继承中对象内存的分布
- 多重继承及虚继承中对象内存的分布
- 多重继承及虚继承中对象内存的分布
- 多重继承及虚继承中对象内存的分布
- 多重继承及虚继承中对象内存的分布
- 多重继承时的指针转换偏移
- 多重继承时的指针转换偏移
- 类对象内存布局,虚函数,虚拟继承和多重继承的实现
- 单一继承下无虚函数覆盖__虚函数表中的虚函数指针的获取
- 单一继承下无虚函数覆盖__虚函数表中的虚函数指针的获取(二)
- lwIP(V1.3.0)RAW_API译文
- C语言数据结构——单链表
- 设置Launch Image 图片
- MAC 苹果电脑如果安装brew
- apktool,dex2jar,jd-gui简单使用与实战
- 【虚函数、虚拟指针、虚表指针】解析多重继承时,虚表的分布
- Android自定义View时使用TypedArray配置样式属性
- window下Tomcat Permgen设置,亲验有效
- 搭建Hadoop源代码阅读环境
- ionic-v1.7.12-ios版修改
- css 常用技巧
- TEST
- MQTT开发总结
- Linux查看某目录下各个文件夹的大小