-
-
[原创]我们来聊聊C++多态吧,理解它,并找到它。
-
发表于:
2019-10-14 19:54
4021
-
[原创]我们来聊聊C++多态吧,理解它,并找到它。
我们通过一段代码,先来了解多态的底层实现
非常简单的类,如果这里没有多态函数的话这个类对象实际只占1个字节(占位字节),有了多态函数后类对象里会保存一张多态函数的地址表,那么这个对象就会占4个字节。
来看反汇编。
CALL指令调用的就是编译器为这个类生成的构造函数,这么简单的类也要有构造函数??,猜的没错,就是用来初始化多态表的,走进去看。
我把多余的代码删掉了,构造函数只做了这一件事情,就是把多态表的指针赋值到对象地址中,也就是文中的this指针。
由上面的代码可以看出,这个类的对象的内存应该如下图:
我们看下 0x577BF8 中保存的内容:
整理一下是这样的,0x005713C0,0x005713BB,0x0000000。
那么这两个有效地址就是我们代码中的两个多态函数,我们来验证下。
so,我们可以总结出,对象的虚表指针在以对象为基址的前4个字节中,虚表指针指向的是一个地址表,地址表中的每一个地址对应这个类中的每一个虚函数。
在上例中,析构函数中做了和构造函数一模一样的事情,因为在构造函数中已经对虚表赋值了,在析构函数中是不是有点多此一举?并不是,析构函数中重新赋值是防止读取的虚表不是自己的虚表,读者可以从继承的角度出发,来思考这个问题。
搞不懂去看我写的继承的文章吧,可能还没更。
重点来了:
虚表信息是在编译后会被链接到二进制文件中,so 虚表是一个固定地址。
虚表中的虚函数地址排序顺序依据虚函数在类中的声明顺序而定。
当虚函数被访问时,会根据对象的首地址,取出虚表地址,在取出虚表元素,需要多次寻址才能完成。
通过间接寻址访问虚表,只发生在使用对象的指针或者引用调用虚函数的时候才会发生,当使用对象调用虚函数,不需要查表访问。(调用自身的函数,未构成多态,查虚表只会降低效率)
------------------------------->找到它
在茫茫汇编代码中找到多态需要关注以下几点:
类中隐式定义了一个数据成员
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-10-14 19:57
被Hasic编辑
,原因: 代码格式化