博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
virtual 虚函数补充
阅读量:3941 次
发布时间:2019-05-24

本文共 3309 字,大约阅读时间需要 11 分钟。

文章目录

inline 声明为虚函数

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 是不起作用的。

static 修饰的静态成员方法能不能声明为虚函数

在这里插入图片描述

静态函数又叫类的成员方法,静态成员函数的调用是不依赖对象的存在的,也就是在创建对象之前,就可以调用静态成员函数。
而虚函数存在于虚函数表中,虚函数表在编译阶段生成,访问虚函数的时候,首先在对象的前四个字节中找到虚函数表的地址,然后在虚函数表中查找相应的虚函数的地址所以说虚函数的访问是依赖对象存在的而静态成员方法不能依赖对象的存在,所以二者是不能兼容的。
关于虚函数表于虚函数指针的内容参考

构造函数能不能是虚函数

在这里插入图片描述

跟前面static 修饰的类似,如果构造函数可以是虚函数,那调用构造函数之前对象并不存在,即无法通过对象的vfptr 指针找到虚函数表的地址,也就无法访问构造函数。
与死锁的原理相似,只有调用构造函数才能产生对象,只有产生对象才能调用构造函数

调用虚函数一定发生动态绑定吗?

通过上面的汇编代码的分析,我们可以看到,动态绑定时调用函数的汇编指令是

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/

你可能感兴趣的文章
从2D恢复出3D的数据
查看>>
glm 中 数据类型 与 原始数据(c++ 数组)之间的转换
查看>>
Derivatives of scalars, vector functions and matrices
查看>>
the jacobian matrix and the gradient matrix
查看>>
VS2010 将背景设为保护色
查看>>
ubutun里面用命令行安装软件
查看>>
ubuntu 常用命令
查看>>
SQLite Tutorial 4 : How to export SQLite file into CSV or Excel file
查看>>
Optimizate objective function in matrix
查看>>
Convert polygon faces to triangles or quadrangles
查看>>
read obj in matlab
查看>>
find out the neighbour matrix of a mesh
查看>>
Operators and special characters in matlab
查看>>
As-Conformal-As-Possible Surface Registration
查看>>
qmake Variable Reference
查看>>
Lesson 2 Gradient Desent
查看>>
find border vertex
查看>>
matlab sliced variable
查看>>
create symbolic array
查看>>
TAUCS库的编译(vs2010)
查看>>