当前位置: 首页 > news >正文

个人电脑做网站服务器网站/搜索引擎排名优化建议

个人电脑做网站服务器网站,搜索引擎排名优化建议,吉林省第二波疫情最新消息,网站数据建设涉及哪些内容前面的从汇编看c中成员函数指针(一)和从汇编看c成员函数指针(二)讨论的要么是单一类,要么是普通的多重继承,没有讨论虚拟继承,下面就来看一看,当引入虚拟继承之后,成员函数指针会有什么变化。 下面来看c源码: #include…

前面的从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的要么是单一类,要么是普通的多重继承,没有讨论虚拟继承,下面就来看一看,当引入虚拟继承之后,成员函数指针会有什么变化。

下面来看c++源码:

#include <cstdio>
using namespace std;class Top {
public:virtual int get1() {return 1;}virtual int get2() {return 2;}
};class Left : virtual public Top {
public:virtual int get3() {return 3;}virtual int get4() {return 4;}
};class Right : virtual public Top {
public:virtual int get5() {return 5;}virtual int get6() {return 6;}
};class Bottom : public Left, public Right {
public:virtual int get1() {return 7;}virtual int get3() {return 8;}virtual int get5() {return 9;}virtual int get7() {return 10;}
};int main() {Bottom b;Bottom* bp = &b;Left* lp = bp;Right* rp = bp;Top* tp = bp;/******************************定义各类指针函数**********************/int(Top::*tgp1)() = &Top::get1;int(Top::*tgp2)() = &Top::get2;int(Left::*lgp1)() = &Left::get1;int(Left::*lgp2)() = &Left::get2;int(Left::*lgp3)() = &Left::get3;int(Left::*lgp4)() = &Left::get4;int(Right::*rgp1)() = &Right::get1;int(Right::*rgp2)() = &Right::get2;int(Right::*rgp5)() = &Right::get5;int(Right::*rgp6)() = &Right::get6;int(Bottom::*bgp1)() = &Bottom::get1;int(Bottom::*bgp2)() = &Bottom::get2;int(Bottom::*bgp3)() = &Bottom::get3;int(Bottom::*bgp4)() = &Bottom::get4;int(Bottom::*bgp5)() = &Bottom::get5;int(Bottom::*bgp6)() = &Bottom::get6;int(Bottom::*bgp7)() = &Bottom::get7;/****************************输出各类成员函数指针的大小*******************/printf("sizeof(tgp1) = %d\n", sizeof(tgp1));printf("sizeof(tgp2) = %d\n", sizeof(tgp2));printf("\n");printf("sizeof(lgp1) = %d\n", sizeof(lgp1));printf("sizeof(lgp2) = %d\n", sizeof(lgp2));printf("sizeof(lgp3) = %d\n", sizeof(lgp3));printf("sizeof(lgp4) = %d\n", sizeof(lgp4));printf("\n");printf("sizeof(rgp1) = %d\n", sizeof(rgp1));printf("sizeof(rgp2) = %d\n", sizeof(rgp2));printf("sizeof(rgp5) = %d\n", sizeof(rgp5));printf("sizeof(rgp6) = %d\n", sizeof(rgp6));printf("\n");printf("sizeof(bgp1) = %d\n", sizeof(bgp1));printf("sizeof(bgp2) = %d\n", sizeof(bgp2));printf("sizeof(bgp3) = %d\n", sizeof(bgp3));printf("sizeof(bgp4) = %d\n", sizeof(bgp4));printf("sizeof(bgp5) = %d\n", sizeof(bgp5));printf("sizeof(bgp6) = %d\n", sizeof(bgp6));printf("sizeof(bgp7) = %d\n", sizeof(bgp7));printf("\n");/*********************************输出各类成员函数指针*****************/printf("&Top::get1 = %lu\n", &Top::get1);printf("&Top::get2 = %lu\n", &Top::get2);printf("&Left::get1 = %lu\n", &Left::get1);printf("&Left::get2 = %lu\n", &Left::get2);printf("&Left::get3 = %lu\n", &Left::get3);printf("&Left::get4 = %lu\n", &Left::get4);printf("&Right::get1 = %lu\n", &Right::get1);printf("&Right::get2 = %lu\n", &Right::get2);printf("&Right::get5 = %lu\n", &Right::get5);printf("&Right::get6 = %lu\n", &Right::get6);printf("&Bottom::get1 = %lu\n", &Bottom::get1);printf("&Bottom::get2 = %lu\n", &Bottom::get2);printf("&Bottom::get3 = %lu\n", &Bottom::get3);printf("&Bottom::get4 = %lu\n", &Bottom::get4);printf("&Bottom::get5 = %lu\n", &Bottom::get5);printf("&Bottom::get6 = %lu\n", &Bottom::get6);printf("&Bottom::get7 = %lu\n", &Bottom::get7);/********************************用成员指针调用各类成员函数*****************/(bp->*bgp1)();(bp->*bgp2)();(bp->*bgp3)();(bp->*bgp4)();(bp->*bgp5)();(bp->*bgp6)();(bp->*bgp7)();}

下面是输出结果:

通过上面的输出,我们可以得到2个信息:

1 当类的继承层次中包含虚基类时,成员函数指针编程了12字节

2 程序中定义了17个成员函数指针,但是只保存了3种不同的地址

对于第2点,通过从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)可以知道,由于所有的成员函数在相应的虚表中相对于虚表首地址只有3中偏移量,0 4 8,因此,只要3个vcall函数就够了,而且vcall函数的功能也一样,通过寄存器ecx传递进来的this指针,得到成员函数所在的正确虚表首地址,然后从虚表中获取成员函数地址,并跳转到该地址处执行。下面是3个vcall函数汇编码:

??_9Top@@$BA@AE PROC                    ; Top::`vcall'{0}', COMDATmov    eax, DWORD PTR [ecx];寄存器ecx保存有this指针,这里将this指针所指向的内存内容(即vftable首地址);给寄存器eaxjmp    DWORD PTR [eax];取eax保存的内存地址里面的内容(即虚表首地址处存储的虚函数地址),然后跳转到该地址执行
??_9Top@@$B3AE PROC                    ; Top::`vcall'{4}', COMDATmov    eax, DWORD PTR [ecx];寄存器ecx保存有this指针,这里将this指针所指向的内存内容(即vftable首地址);给寄存器eaxjmp    DWORD PTR [eax+4];取偏移eax保存的内存地址4byte处的内存内容(即偏移虚表首地址4byte处内存存储的虚函数地址),然后跳转到该地址执行

??_9Bottom@@$B7AE PROC                    ; Bottom::`vcall'{8}', COMDATmov    eax, DWORD PTR [ecx];寄存器ecx保存有this指针,这里将this指针所指向的内存内容(即vftable首地址);给寄存器eaxjmp    DWORD PTR [eax+8];取偏移eax保存的内存地址8byte处的内存内容(即偏移虚表首地址8byte处内存存储的虚函数地址),然后跳转到该地址执行

下面是类Bottom的继承关系图(菱形继承)

下面是各个类的类存布局:

       

下面就来看看引入虚拟继承之后,成员函数指针存储的是什么值。

下面来看定义这些成员指针变量的汇编码:

60   :     int(Top::*tgp1)() = &Top::get1;
mov    DWORD PTR _tgp1$[ebp], OFFSET ??_9Top@@$BA@AE ; `vcall'{0}'将??_9Top@@$BA@AE所代表的内存地址给tgp1 即存储vcall{0}的地址; 61   :     int(Top::*tgp2)() = &Top::get2;mov    DWORD PTR _tgp2$[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}' 同定义tgp1; 62   :     int(Left::*lgp1)() = &Left::get1;mov    DWORD PTR $T4213[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}';将OFFSET ??_9Top@@$BA@AE所代表的的内存地址(vcall{0}地址)给临时对象ST4213首地址处内存mov    DWORD PTR $T4213[ebp+4], 0;将0给偏移临时对象ST4213首地址4byte处内存mov    DWORD PTR $T4213[ebp+8], 4;将4给偏移临时对象ST4213首地址8byte处内存mov    ecx, DWORD PTR $T4213[ebp];将临时对象ST4213首地址处内存内容给寄存器ecxmov    DWORD PTR _lgp1$[ebp], ecx;将寄存器ecx的值给lgp1首地址处内存mov    edx, DWORD PTR $T4213[ebp+4];将偏移临时对象ST4213首地址4byte处内存内容给寄存器edxmov    DWORD PTR _lgp1$[ebp+4], edx;将edx的值给偏移lgp1首地址4byte处内存mov    eax, DWORD PTR $T4213[ebp+8];将偏移临时对象ST4213首地址8byte处内存内容给寄存器eaxmov    DWORD PTR _lgp1$[ebp+8], eax;将eax的值给偏移lgp1首地址8byte处内存; 63   :     int(Left::*lgp2)() = &Left::get2;;同定义lgp1mov    DWORD PTR $T4214[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4214[ebp+4], 0mov    DWORD PTR $T4214[ebp+8], 4mov    ecx, DWORD PTR $T4214[ebp]mov    DWORD PTR _lgp2$[ebp], ecxmov    edx, DWORD PTR $T4214[ebp+4]mov    DWORD PTR _lgp2$[ebp+4], edxmov    eax, DWORD PTR $T4214[ebp+8]mov    DWORD PTR _lgp2$[ebp+8], eax; 64   :     int(Left::*lgp3)() = &Left::get3;;同定义lgp1mov    DWORD PTR $T4215[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4215[ebp+4], 0mov    DWORD PTR $T4215[ebp+8], 0mov    ecx, DWORD PTR $T4215[ebp]mov    DWORD PTR _lgp3$[ebp], ecxmov    edx, DWORD PTR $T4215[ebp+4]mov    DWORD PTR _lgp3$[ebp+4], edxmov    eax, DWORD PTR $T4215[ebp+8]mov    DWORD PTR _lgp3$[ebp+8], eax; 65   :     int(Left::*lgp4)() = &Left::get4;;同定义lgp1mov    DWORD PTR $T4216[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4216[ebp+4], 0mov    DWORD PTR $T4216[ebp+8], 0mov    ecx, DWORD PTR $T4216[ebp]mov    DWORD PTR _lgp4$[ebp], ecxmov    edx, DWORD PTR $T4216[ebp+4]mov    DWORD PTR _lgp4$[ebp+4], edxmov    eax, DWORD PTR $T4216[ebp+8]mov    DWORD PTR _lgp4$[ebp+8], eax; 66   :     int(Right::*rgp1)() = &Right::get1;;同定义lgp1mov    DWORD PTR $T4217[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4217[ebp+4], 0mov    DWORD PTR $T4217[ebp+8], 4mov    ecx, DWORD PTR $T4217[ebp]mov    DWORD PTR _rgp1$[ebp], ecxmov    edx, DWORD PTR $T4217[ebp+4]mov    DWORD PTR _rgp1$[ebp+4], edxmov    eax, DWORD PTR $T4217[ebp+8]mov    DWORD PTR _rgp1$[ebp+8], eax; 67   :     int(Right::*rgp2)() = &Right::get2;;同定义lgp1mov    DWORD PTR $T4218[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4218[ebp+4], 0mov    DWORD PTR $T4218[ebp+8], 4mov    ecx, DWORD PTR $T4218[ebp]mov    DWORD PTR _rgp2$[ebp], ecxmov    edx, DWORD PTR $T4218[ebp+4]mov    DWORD PTR _rgp2$[ebp+4], edxmov    eax, DWORD PTR $T4218[ebp+8]mov    DWORD PTR _rgp2$[ebp+8], eax; 68   :     int(Right::*rgp5)() = &Right::get5;;同定义lgp1mov    DWORD PTR $T4219[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4219[ebp+4], 0mov    DWORD PTR $T4219[ebp+8], 0mov    ecx, DWORD PTR $T4219[ebp]mov    DWORD PTR _rgp5$[ebp], ecxmov    edx, DWORD PTR $T4219[ebp+4]mov    DWORD PTR _rgp5$[ebp+4], edxmov    eax, DWORD PTR $T4219[ebp+8]mov    DWORD PTR _rgp5$[ebp+8], eax; 69   :     int(Right::*rgp6)() = &Right::get6;;同定义lgp1mov    DWORD PTR $T4220[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4220[ebp+4], 0mov    DWORD PTR $T4220[ebp+8], 0mov    ecx, DWORD PTR $T4220[ebp]mov    DWORD PTR _rgp6$[ebp], ecxmov    edx, DWORD PTR $T4220[ebp+4]mov    DWORD PTR _rgp6$[ebp+4], edxmov    eax, DWORD PTR $T4220[ebp+8]mov    DWORD PTR _rgp6$[ebp+8], eax; 70   :     int(Bottom::*bgp1)() = &Bottom::get1;;同定义lgp1mov    DWORD PTR $T4221[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4221[ebp+4], 0mov    DWORD PTR $T4221[ebp+8], 4mov    ecx, DWORD PTR $T4221[ebp]mov    DWORD PTR _bgp1$[ebp], ecxmov    edx, DWORD PTR $T4221[ebp+4]mov    DWORD PTR _bgp1$[ebp+4], edxmov    eax, DWORD PTR $T4221[ebp+8]mov    DWORD PTR _bgp1$[ebp+8], eax; 71   :     int(Bottom::*bgp2)() = &Bottom::get2;;同定义lgp1mov    DWORD PTR $T4222[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4222[ebp+4], 0mov    DWORD PTR $T4222[ebp+8], 4mov    ecx, DWORD PTR $T4222[ebp]mov    DWORD PTR _bgp2$[ebp], ecxmov    edx, DWORD PTR $T4222[ebp+4]mov    DWORD PTR _bgp2$[ebp+4], edxmov    eax, DWORD PTR $T4222[ebp+8]mov    DWORD PTR _bgp2$[ebp+8], eax; 72   :     int(Bottom::*bgp3)() = &Bottom::get3;;同定义lg1mov    DWORD PTR $T4223[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4223[ebp+4], 0mov    DWORD PTR $T4223[ebp+8], 0mov    ecx, DWORD PTR $T4223[ebp]mov    DWORD PTR _bgp3$[ebp], ecxmov    edx, DWORD PTR $T4223[ebp+4]mov    DWORD PTR _bgp3$[ebp+4], edxmov    eax, DWORD PTR $T4223[ebp+8]mov    DWORD PTR _bgp3$[ebp+8], eax; 73   :     int(Bottom::*bgp4)() = &Bottom::get4;;同定义lgp1mov    DWORD PTR $T4224[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}'mov    DWORD PTR $T4224[ebp+4], 0mov    DWORD PTR $T4224[ebp+8], 0mov    ecx, DWORD PTR $T4224[ebp]mov    DWORD PTR _bgp4$[ebp], ecxmov    edx, DWORD PTR $T4224[ebp+4]mov    DWORD PTR _bgp4$[ebp+4], edxmov    eax, DWORD PTR $T4224[ebp+8]mov    DWORD PTR _bgp4$[ebp+8], eax; 74   :     int(Bottom::*bgp5)() = &Bottom::get5;;同定义lgp1mov    DWORD PTR $T4225[ebp], OFFSET ??_9Top@@$BA@AE ; Top::`vcall'{0}'mov    DWORD PTR $T4225[ebp+4], 8mov    DWORD PTR $T4225[ebp+8], 0mov    ecx, DWORD PTR $T4225[ebp]mov    DWORD PTR _bgp5$[ebp], ecxmov    edx, DWORD PTR $T4225[ebp+4]mov    DWORD PTR _bgp5$[ebp+4], edxmov    eax, DWORD PTR $T4225[ebp+8]mov    DWORD PTR _bgp5$[ebp+8], eax; 75   :     int(Bottom::*bgp6)() = &Bottom::get6;;这里只给出程序要执行的汇编码的注释mov    DWORD PTR $T4226[ebp], OFFSET ??_9Top@@$B3AE ; Top::`vcall'{4}';将??_9Top@@$B3AE所代表的内存地址(即vcall{4}的地址)给临时对象ST4226的首地址处内存xor    ecx, ecx;将ecx寄存器里面的值异或,这是不论ecx里面的值为什么,都为0jne    SHORT $LN7@main;如果上面异或结果不为0,就跳转到标号$LN7@main处执行,否则,顺序执行,这里显然顺序执行mov    DWORD PTR tv90[ebp], 8;将8给临时变量tv90jmp    SHORT $LN8@main;跳转到标号$LN8@main处执行
$LN7@main:mov    DWORD PTR tv90[ebp], 0
$LN8@main:mov    edx, DWORD PTR tv90[ebp];将临时变量tv90的值给寄存器edxmov    DWORD PTR $T4226[ebp+4], edx;i将edx的值给偏移临时对象ST4226首地址4byte处内存mov    DWORD PTR $T4226[ebp+8], 0;将0给偏移临时对象ST4226首地址8byte处内存mov    eax, DWORD PTR $T4226[ebp];将临时对象ST4226首地址处内存内容给寄存器eaxmov    DWORD PTR _bgp6$[ebp], eax;将寄存器eax的内容给bgp6首地址处内存mov    ecx, DWORD PTR $T4226[ebp+4];将偏移临时对象ST4226首地址4byte处内存内容给寄存器ecxmov    DWORD PTR _bgp6$[ebp+4], ecx;将ecx的值给偏移bgp6首地址4byte处内存mov    edx, DWORD PTR $T4226[ebp+8];将偏移临时对象ST4226首地址8byte处内存给寄存器edxmov    DWORD PTR _bgp6$[ebp+8], edx;将edx的值给偏移bgp6首地址8byte处内存; 76   :     int(Bottom::*bgp7)() = &Bottom::get7;;同定义lgp1mov    DWORD PTR $T4229[ebp], OFFSET ??_9Bottom@@$B7AE ; Bottom::`vcall'{8}'mov    DWORD PTR $T4229[ebp+4], 0mov    DWORD PTR $T4229[ebp+8], 0mov    eax, DWORD PTR $T4229[ebp]mov    DWORD PTR _bgp7$[ebp], eaxmov    ecx, DWORD PTR $T4229[ebp+4]mov    DWORD PTR _bgp7$[ebp+4], ecxmov    edx, DWORD PTR $T4229[ebp+8]mov    DWORD PTR _bgp7$[ebp+8], edx

下面给出给成员函数指针保存的值的图示

               

                             

           

 

成员函数指针保存的值清楚了,但是这些值又有什么意义呢?下面我们通过bgp1~bgp7成员函数指针来调用虚函数的汇编码来进行分析:

121  :     (bp->*bgp1)();
mov    edx, DWORD PTR _bp$[ebp];将对象b的首地址给寄存器edxmov    eax, DWORD PTR [edx+4];edx+4得到偏移对象b首地址4byte处内存地址,这里将该内存地址内容(vbtable首地址)给寄存器eaxmov    ecx, DWORD PTR _bgp1$[ebp+8];将偏移对象bgp1首地址8byte处内存内容给寄存器ecxmov    edx, DWORD PTR [eax+ecx];eax = vbtable首地址 ecx = 4 eax + ecx得到偏移vbtable首地址4byte处内存地址;这里取偏移vbtable首地址4byte处内存内容(即vbtable指针偏移虚基类Top子对象首地址的偏移量)给寄存器edxmov    eax, DWORD PTR _bp$[ebp];将对象b的首地址给寄存器eaxlea    ecx, DWORD PTR [eax+edx+4];eax = 对象b首地址 edx = 即vbtable指针偏移虚基类Top子对象首地址的偏移量 eax + edx + 4 = 对象b中虚基类Top子对象的首地址add    ecx, DWORD PTR _bgp1$[ebp+4];将偏移bgp1首地址4byte处内存内容(为0)与ecx里面的内容相加,得到对象b中虚基类Top子对象首地址;结果保存在寄存器ecx里面,将作为隐含参数传给相应的vcall函数call    DWORD PTR _bgp1$[ebp];bgp1首地址处内存存有相应的vcall函数地址,这里调用相应的vcall函数;从这段汇编码中可以发现bgp1的第三项存储的是偏移vbtable首地址的偏移量,而第二项是;成员函数所在类相对于对象b中虚基类Top子对象首地址的偏移量; 122  :     (bp->*bgp2)();;同bgp1的调用mov    ecx, DWORD PTR _bp$[ebp]mov    edx, DWORD PTR [ecx+4]mov    eax, DWORD PTR _bgp2$[ebp+8]mov    ecx, DWORD PTR [edx+eax]mov    edx, DWORD PTR _bp$[ebp]lea    ecx, DWORD PTR [edx+ecx+4]add    ecx, DWORD PTR _bgp2$[ebp+4]call    DWORD PTR _bgp2$[ebp]; 123  :     (bp->*bgp3)();mov    eax, DWORD PTR _bp$[ebp];将对象b的首地址给eax寄存器mov    ecx, DWORD PTR [eax+4];eax = 对象b首地址 eax + 4 = 偏移对象b首地址4byte处内存地址;这里将偏移对象b对象首地址4byte内存地址内容(即vbtable首地址)给寄存器ecxmov    edx, DWORD PTR _bgp3$[ebp+8];将偏移对象bgp3首地址8byte处内存内容(为0)给寄存器edxmov    eax, DWORD PTR [ecx+edx];ecx = vbtable首地址 edx = 0 ecx + edx = vbtable首地址;这里取vbtable首地址处的内存内容(即vbtable指针偏移对象b首地址的偏移量,为-4)给寄存器eaxmov    ecx, DWORD PTR _bp$[ebp];将对象b的首地址给寄存器ecxlea    ecx, DWORD PTR [ecx+eax+4];ecx = 对象b首地址 eax = -4 ecx + eax + 4 = ecx(即对象b首地址);这里将对象b首地址给寄存器ecxadd    ecx, DWORD PTR _bgp3$[ebp+4];将偏移对象bgp3首地址4byte处内存内容(为0)与ecx相加 得到对象b首地址 结果保存在ecx寄存器中;ecx的值将作为隐含参数传递给相应的vcall函数call    DWORD PTR _bgp3$[ebp];bgp3首地址处内存存有相应vcall函数地址,这里调用vcall函数;通过分析可知,bgp3第三项保存的仍然是偏移vbtable首地址的偏移量;第二项确实成员函数所在类偏移对象b的首地址的偏移量,与bgp1不同; 124  :     (bp->*bgp4)();;同bgp3调用mov    edx, DWORD PTR _bp$[ebp]mov    eax, DWORD PTR [edx+4]mov    ecx, DWORD PTR _bgp4$[ebp+8]mov    edx, DWORD PTR [eax+ecx]mov    eax, DWORD PTR _bp$[ebp]lea    ecx, DWORD PTR [eax+edx+4]add    ecx, DWORD PTR _bgp4$[ebp+4]call    DWORD PTR _bgp4$[ebp]; 125  :     (bp->*bgp5)();;同bgp3调用mov    ecx, DWORD PTR _bp$[ebp]mov    edx, DWORD PTR [ecx+4]mov    eax, DWORD PTR _bgp5$[ebp+8]mov    ecx, DWORD PTR [edx+eax]mov    edx, DWORD PTR _bp$[ebp]lea    ecx, DWORD PTR [edx+ecx+4]add    ecx, DWORD PTR _bgp5$[ebp+4]call    DWORD PTR _bgp5$[ebp]; 126  :     (bp->*bgp6)();;同bgp3调用mov    eax, DWORD PTR _bp$[ebp]mov    ecx, DWORD PTR [eax+4]mov    edx, DWORD PTR _bgp6$[ebp+8]mov    eax, DWORD PTR [ecx+edx]mov    ecx, DWORD PTR _bp$[ebp]lea    ecx, DWORD PTR [ecx+eax+4]add    ecx, DWORD PTR _bgp6$[ebp+4]call    DWORD PTR _bgp6$[ebp]; 127  :     (bp->*bgp7)();;同bgp3调用mov    edx, DWORD PTR _bp$[ebp]mov    eax, DWORD PTR [edx+4]mov    ecx, DWORD PTR _bgp7$[ebp+8]mov    edx, DWORD PTR [eax+ecx]mov    eax, DWORD PTR _bp$[ebp]lea    ecx, DWORD PTR [eax+edx+4]add    ecx, DWORD PTR _bgp7$[ebp+4]call    DWORD PTR _bgp7$[ebp]

通过上面的汇编码可以发现,包含虚拟继承的成员函数指针第一项保存的仍然是相应vcall函数的地址,第二项保存的是成员函数所属类相对于对象b首地址的偏移量(但是指向虚基类成员函数的指针有所不同,如bgp1和bgp2,他们保存的是成员函数所属类相对于虚基类Top首地址的偏移量),第三项保存的是相对于vbtable首地址的偏移量。

可以看到,与普通的多重继承相比,包含虚拟继承的成员函数指针还保留了有关vbtable的信息,这是因为,由于虚基类的特殊性(即它的位置在每次子类派生之后,都不一样,而非虚基类在子类中都有固定的偏移量),想要定位虚基类的首地址,必须通过vbtable。

同从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的一样,包含虚拟继承的时候,也可以将基类成员函数指针绑定到派生类对象或者派生类对象指针上,如可以(bp->*lgp1)(),编译器做内部转话(即将this指着从指向派生类对象首地址调整到指向派生类中基类子对象首地址处),但是不能将派生类成员函数指针绑定到基类对象或者基类对象指针上。

同从汇编看c++中成员函数指针(一)和从汇编看c++成员函数指针(二)讨论的一样,包含虚拟继承的时候,也可以将基类成员成员指针转换为派生类成员函数指针,如可以bgp1 = lgp1,但是不能讲派生类成员函数指针转换为基类成员函数指针。

 

 

 

http://www.jmfq.cn/news/4962385.html

相关文章:

  • 免费建站软件哪个最好/seo入门培训课程
  • 网站能找到做网站的人/常用的网站推广方法
  • 深圳做网站应该怎么做/便民信息微信平台推广
  • 哪个网站可以做c语言的题/网站规划
  • 济宁网站建设神华科技/面点培训学校哪里有
  • vb net 做网站/百度竞价排名
  • 自己做网站需要钱吗/seo技术培训江门
  • 网页二级页面设计/百度seo排名优化软件
  • 有网站了怎么做app/江门网站建设模板
  • 网站建设的市场策划/营销推广
  • 竭诚网络网站建设开发/郑州seo技术顾问
  • 可以做数学题的网站/链接地址
  • 怎么把自己的网站放到百度上/营销策略有哪些理论
  • 移动互联网开发技术是什么/站长工具seo综合查询引流
  • 公司网站登陆后台管理中心不能修改前台主页/百度seo查询
  • 西安网站推广公司电话/百度统计流量研究院
  • 做商城网站要什么证件/seo排名优化软件有用吗
  • 教育行业网站制作/重庆网站到首页排名
  • 以绿色为主的网站/上海何鹏seo
  • 网站建设怎么管理业务员/网站结构优化的内容和方法
  • 企业网站管理系统免费/优化推广公司哪家好
  • 辽宁省建设安全监督网网站/seo网站推广如何做
  • 南京专业网站营销/北京网站优化外包
  • 大连鼎信网站建设公司/网站建设需要多少钱
  • 全国做网站的/简述seo的基本步骤
  • 最好的科技资讯网站/企业网站推广渠道有哪些
  • 淄博哪个网站做房屋出赁好/精准防控高效处置
  • 网站备案密码使用/搜索引擎营销分析
  • 租办公室/重庆seo技术教程博客
  • 怎么在南京人社网站做失业登记/南宁 百度网盘