本文共 3309 字,大约阅读时间需要 11 分钟。
class Base{ public: //这里将内联函数声明为虚函数 virtual inline void Show() { cout << "Base::show()" << endl; }private: int ma;};class Derived:public Base{ public: void Show() { cout << "Derived::Show()" << endl; }};int main(){ Base* p = new Derived(); p->Show(); return 0;}
这里分析一下p->Show()的反汇编代码
p->Show(); //将p的里面存的值放到eax寄存器, 这里是Derived对象的地址00864B1D mov eax,dword ptr [p] //将eax(Derived) 里面的值的前四个字节(dword 双字)的内容放到edx寄存器 //这里是vfptr的值,因为该对象的前四个字节是虚函数表的地址00864B20 mov edx,dword ptr [eax] //将esp 寄存器的内容放在 esi 寄存器00864B22 mov esi,esp //将p指向的地址存放在ecx中 00864B24 mov ecx,dword ptr [p] //取出虚函数表的前四个字节,(第一个虚函数的地址)00864B27 mov eax,dword ptr [edx] //调用虚函数00864B29 call eax
因为inline是将函数的代码在调用处展开,不存在函数栈帧的开辟,更没有函数地址,而虚函数表中存储的是每个虚函数的地址,所以这里的inline 是不起作用的。
通过上面的汇编代码的分析,我们可以看到,动态绑定时调用函数的汇编指令是
call eax 直接call 一个 寄存器,而静态绑定通常是call + 地址,这里通过这个特征看一下什么时候动态绑定,什么时候静态绑定int main(){ //通过对象进行调用 Derived d; d.Show();} Derived d;00C34A41 call Derived::Derived (0C31564h) d.Show();00C34A46 lea ecx,[d] //通过对象调用是静态绑定00C34A49 call Derived::Show (0C3155Fh)
int main(){ //通过基类指针访问 Base* p = new Derived(); p->Show(); return 0;} p->Show();00F84A7D mov eax,dword ptr [p] 00F84A80 mov edx,dword ptr [eax] 00F84A82 mov esi,esp 00F84A84 mov ecx,dword ptr [p] 00F84A87 mov eax,dword ptr [edx] //动态绑定00F84A89 call eax
这里不一一测试,通过基类指针或引用,派生类指针或引用访问都是动态绑定 通过对象访问都是静态绑定
前面说过虚函数的动态绑定依赖于对象的存在,构造函数结束之前对象还没有存在,所以在构造函数中调用虚函数,应该是静态绑定,这里给出验证
class Base{ public: Base() { Show(); } virtual void Show() { cout << "Base::show()" << endl; }private: int ma;};int main(){ Base p; p.Show(); return 0;}//汇编指令 Base p;00974ACE lea ecx,[p] //这里进入构造函数00974AD1 call Base::Base (097155Ah) /***********************构造函数中************************/0097497F pop ecx 00974980 mov dword ptr [this],ecx 00974983 mov eax,dword ptr [this] 00974986 mov dword ptr [eax],97DD60h 0097498C mov ecx,dword ptr [this] //静态绑定0097498F call Base::Show (0971555h)
这个要分两种情况
首先,析构函数是虚函数class Base{ public: virtual void Show() { cout << "Base::show()" << endl; } virtual ~Base() { Show(); }private: int ma;};int main(){ Base *p = new Base(); delete p; return 0;}00904B5F mov edx,dword ptr [ebp-0E0h] 00904B65 mov eax,dword ptr [edx] 00904B67 mov ecx,dword ptr [ebp-0E0h] 00904B6D mov edx,dword ptr [eax+4] //动态绑定00904B70 call edx
析构函数是普通函数
class Base{ public: virtual void Show() { cout << "Base::show()" << endl; } ~Base() { Show(); }private: int ma;};int main(){ Base *p = new Base(); delete p; return 0;}01092D70 mov dword ptr [this],ecx 01092D73 mov ecx,dword ptr [this] //静态绑定01092D76 call Base::~Base (01091578h)
转载地址:http://exnwi.baihongyu.com/