对象中方法调用时,代码位置的问题
发布网友
发布时间:2022-04-25 20:10
我来回答
共5个回答
热心网友
时间:2022-06-17 01:35
首先,相对于类基址来说,函数的位置是固定的,那么在VC的RTTI机制(运行时类别标识)在你定义类的时候会将你的程序中用到的类用链表的方式连接起来,当你调用用Myobject的时候,他先会去判断类,然后根据函数名利用判断得到类型的结果直接定位,RTTI具体可以去看候捷的<深入浅出MFC>中的六大仿真技术.
第二个你说的CALL ECX +18 之类的,你可以从DLL入手分析,首先你加载到程序,然后得到他的地址,那么ecx假设就是当前DLL函数偏移表的首地址,设置偏移后会得到目标函数的地址,然后执行,如果想知道他们代表什么函数,你可以选择用PEDUMP.exe,在MSDN中搜,可以搜到源码,VS中也带,主要是查看PE文件的结构,主要包括DOS头,NT头,各个区块,包括.TEXT.DATA.CODE等等区块,最重要的就是输入输出表,在输入表中有加载其它DLL的信息,当你枚举出所有加载的DLL后,每个DLL又可以查到调用的函数以及偏移地址,你可以学习一下PE文件的结构,更有助于你解决你现在的问题.PEDUMP我将它修改成GUI的.如图:
热心网友
时间:2022-06-17 01:36
虚函数,是通过虚函数表来动态定位(程序运行时候查表找到函数地址定位的)。
普通函数和成员变量是在源程序编译时候就确定了地址的。当然这个地址是相对地址。
一个PE文件(DLL 或者 EXE )文件,有个函数跳转表头( JMP 0Xxxxx),记录当前文件程序内所使用的所有函数(包括内部函数,和使用的外部导入函数),程序内部二进制机器码调用函数的地方,函数地址就是指向的这些表头的相应函数位置,二进制程序代码是固定的,而表头里面的函数实际入口地址都是在PE文件装入的时候动态设定的,这样二进制代码执行的时候就能跳转到正确的地址。
——这点,你可以通过VC调试程序,使用F11观察函数调用过程就可以看出。
ITypeLib 是类型库接口。调用成员函数是虚函数方式调用的,call [ecx+10],call [ecx+18] :ecx 里记录的虚函数表首地址,表示调用第四个第六个函数。(成员虚函数顺序是按照源码中定义顺序排列的)。
热心网友
时间:2022-06-17 01:36
对于你的问题,推荐一本书,讲的很透彻
书名:<Thinking in C++>
下面是我看这本书时的一段笔记:
C++要求在基类中声明函数时使用virtual,晚*只对virtual起作用,而且只在使用含有虚函数的基类地址时发生。仅需在声明时使用virtual。若基类中为virtual,所有的派生类中都是虚函数。在派生类中virtual的重定义称为重写。
典型的编译器对每个包含虚函数的类创建一个表(Vtable),表中放置特定类的虚函数的地址。类中秘密放置一个虚指针(VPointer),指向虚表。当通过基类指针做虚函数调用时,编译器静态的插入能取得虚指针和虚表中查找函数地址的代码,从而调用正确的函数并引起晚*。
类中不带虚函数,对象长度为期望的成员变量长度之和。若带有虚函数,则增加一个void指针长度,表明无论一个还是多个虚函数,编译器只在结构中插入单个指针。
每当创建或派生一个包含虚函数的类时,编译器为该类创建一个惟一的虚表。表中放置了类或基类中所有已声明为virtual的函数的地址。若派生类没有对基类的虚函数重新定义,就使用基类的虚函数地址,然后在类中放置虚指针,初始化为指向相应的虚表的起始地址。
当通过基类地址调用虚函数时,从基类指针开始,指向对象的起始地址。而虚指针常常在对象的开头,无论什么类型,所有的虚表都具有相同的顺序,必定知道某函数在某个位置。因为获取虚指针和实际函数地址发生在运行时,所以得到晚*。
向上类型转换仅处理地址,若编译器有一个确切类型的对象,那么对任何函数的调用不再使用晚*。
Base* pb=&dog; Base& pb1=dog; pb和pb1可能表示base地址,也可能表示派生对象的地址,必须使用虚函数。 Base pb2; pb2.f(); pb2为确切类型的对象,可以使用早*。
热心网友
时间:2022-06-17 01:37
如果是虚函数那么在调用的时候是用查表的方法,每一个类都会有自己的虚函数表.
如果是普通函数就是直接定位到内存地址的.你看到的代码是这样子的:MyObject1->IsName
在编译的时候编译器会把它转换成另外一种方式,差不多就是:类名@函数名
根据编译器的不同可能有不同,但是道理是一样的,类函数都会被转换成一个类似常量的东西,他的地址是固定的,所以在运行期可以直接定位到该函数.
LZ如果还有问题可以HI我
虚函数表里只存虚函数的内存地址,LZ应该知道什么是虚函数吧?
热心网友
时间:2022-06-17 01:38
据我所知,类经过定义,在编译的时候函数地址就相对定下来了,每个类对象的建立分配一个内存块,其中只是引用了函数的地址,你要通过地址反向解析出函数名,可能牵扯到函数描述,这个可能比较复杂,比如最新的SOA架构中,这种思想就是存在的,通过SOAP描述每个服务端存在的服务,都是通过XML来描述和解析的,但是在编译器里有没有这套机制,你就要请达人帮忙了。