欢迎来到天天文库
浏览记录
ID:9401710
大小:231.00 KB
页数:16页
时间:2018-04-30
《类的虚函数和非虚函数调用自己分析》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、一、多重继承,C继承自A和B其类结构如下图(图2):虚表指针__vfptr(0x00AC780C)A数据成员区:A::m_i(0x11223344)B数据成员区:B::m_i(0x55667788)C数据成员区:C::m_i(0x99aabbcc)第一个虚函数的地址:A::VF()0x00AC1122A::VF()函数入口,实际为VF(A*constthis){cout<<"A::VF()"<2、值内存地址内存值内存地址A部分B部分类C上面代码中主函数如为:int_tmain(intargc,_TCHAR*argv[]){C*pc=newC;//pc=0x0046B3F0A*pa=pc;//pa=0x0046B3F0B*pb=pc;//pb=0x0046B3F0+8=0x0046B3F8system("pause");return0;}对下面代码:int_tmain(intargc,_TCHAR*argv[]){Bb;//设B的地址为XXXC*pc=(C*)(&b);//相当于C*pc=static_cast(&b)。根据图2的类结构中C和B的位置关3、系//(编译器可能认为B的地址比C的地址大8,所以C的地址为B的地址减去8),可知pc=XXX-8。此时可以想像出右边的类Cpc->VF();//错误。如正确,在(XXX-8)处获取虚表指针,但pc存放的是其他数据,故无法调用虚函数,产生错误。system("pause");return0;}其他数据其他数据B::m_i(0x55667788)XXX内存值内存地址B类CXXX-8而下面代码却能正确执行:int_tmain(intargc,_TCHAR*argv[]){Aa;//设A的地址为XXXC*pc=(C*)(&a);//相当于C*pc=static_cast<4、C*>(&a)。根据图2的类结构中C和A的位置关系//(相等),可知pc=XXXpc->VF();//正确,有多态,调用的VF()为实际内存对象的函数,即调用A::VF()。在XXX处获取虚表指针,能正确调用虚函数VF()。cout<m_i<m_i的值随机,//因为此处内存并未被C对象使用或赋值,而可能是其他对象的内存空间。system("pause");return0;}虚表指针__vfptrA数据成员区:A::m_i(0x115、223344)C::m_i(未赋值)内存值内存地址A类CXXXA::VF()函数入口,实际为VF(A*constthis)。。。。。。。。。..而如果B类中也有虚函数,如:classA{public:intm_i;A():m_i(0x11223344){}virtualvoidVF(){cout<<"A::VF()"<6、l;}};classC:publicA,publicB{public:intm_i;C():m_i(0x99aabbcc){}virtualvoidVF(){cout<<"C::VF()"<VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VG()并调用C::VG()pc->VG();//因为VG()是B类中的,C类并未重写,所以先找到C类中B类起始地址(XXX+8),//再在(XXX+8)处的B虚表指针所指的虚表中找到B7、::VG()并调用B::VG()。可以参照下面的反汇编代码。B*pb=(B*)(pc);//由下图3类结构知,pb=XXX+8,pb能访问内存大小为下图3中B部分的8字节(B虚表指针__vfptr和B数据成员B::m_i)pb->VG();//直接在(XXX+8)处的B虚表指针所指的虚表中找到B::VG()并调用B::VG()A*pa=(A*)(pc);//由下图3类结构知,pa=XXX,pa能访问内存大小为下图3中A部分的8字节(A虚表指针__vfptr和A数据成员A::m_i)pa->VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VF()并调
2、值内存地址内存值内存地址A部分B部分类C上面代码中主函数如为:int_tmain(intargc,_TCHAR*argv[]){C*pc=newC;//pc=0x0046B3F0A*pa=pc;//pa=0x0046B3F0B*pb=pc;//pb=0x0046B3F0+8=0x0046B3F8system("pause");return0;}对下面代码:int_tmain(intargc,_TCHAR*argv[]){Bb;//设B的地址为XXXC*pc=(C*)(&b);//相当于C*pc=static_cast(&b)。根据图2的类结构中C和B的位置关
3、系//(编译器可能认为B的地址比C的地址大8,所以C的地址为B的地址减去8),可知pc=XXX-8。此时可以想像出右边的类Cpc->VF();//错误。如正确,在(XXX-8)处获取虚表指针,但pc存放的是其他数据,故无法调用虚函数,产生错误。system("pause");return0;}其他数据其他数据B::m_i(0x55667788)XXX内存值内存地址B类CXXX-8而下面代码却能正确执行:int_tmain(intargc,_TCHAR*argv[]){Aa;//设A的地址为XXXC*pc=(C*)(&a);//相当于C*pc=static_cast<
4、C*>(&a)。根据图2的类结构中C和A的位置关系//(相等),可知pc=XXXpc->VF();//正确,有多态,调用的VF()为实际内存对象的函数,即调用A::VF()。在XXX处获取虚表指针,能正确调用虚函数VF()。cout<m_i<m_i的值随机,//因为此处内存并未被C对象使用或赋值,而可能是其他对象的内存空间。system("pause");return0;}虚表指针__vfptrA数据成员区:A::m_i(0x11
5、223344)C::m_i(未赋值)内存值内存地址A类CXXXA::VF()函数入口,实际为VF(A*constthis)。。。。。。。。。..而如果B类中也有虚函数,如:classA{public:intm_i;A():m_i(0x11223344){}virtualvoidVF(){cout<<"A::VF()"<6、l;}};classC:publicA,publicB{public:intm_i;C():m_i(0x99aabbcc){}virtualvoidVF(){cout<<"C::VF()"<VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VG()并调用C::VG()pc->VG();//因为VG()是B类中的,C类并未重写,所以先找到C类中B类起始地址(XXX+8),//再在(XXX+8)处的B虚表指针所指的虚表中找到B7、::VG()并调用B::VG()。可以参照下面的反汇编代码。B*pb=(B*)(pc);//由下图3类结构知,pb=XXX+8,pb能访问内存大小为下图3中B部分的8字节(B虚表指针__vfptr和B数据成员B::m_i)pb->VG();//直接在(XXX+8)处的B虚表指针所指的虚表中找到B::VG()并调用B::VG()A*pa=(A*)(pc);//由下图3类结构知,pa=XXX,pa能访问内存大小为下图3中A部分的8字节(A虚表指针__vfptr和A数据成员A::m_i)pa->VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VF()并调
6、l;}};classC:publicA,publicB{public:intm_i;C():m_i(0x99aabbcc){}virtualvoidVF(){cout<<"C::VF()"<VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VG()并调用C::VG()pc->VG();//因为VG()是B类中的,C类并未重写,所以先找到C类中B类起始地址(XXX+8),//再在(XXX+8)处的B虚表指针所指的虚表中找到B
7、::VG()并调用B::VG()。可以参照下面的反汇编代码。B*pb=(B*)(pc);//由下图3类结构知,pb=XXX+8,pb能访问内存大小为下图3中B部分的8字节(B虚表指针__vfptr和B数据成员B::m_i)pb->VG();//直接在(XXX+8)处的B虚表指针所指的虚表中找到B::VG()并调用B::VG()A*pa=(A*)(pc);//由下图3类结构知,pa=XXX,pa能访问内存大小为下图3中A部分的8字节(A虚表指针__vfptr和A数据成员A::m_i)pa->VF();//直接在XXX处的A虚表指针所指的虚表中找到C::VF()并调
此文档下载收益归作者所有