从汇编角度看虚函数和普通成员函数的调用过程

本篇文章直入正题。

我们的类成员函数分为inline、virtual、static、normal。

**normal成员函数:**其地址和一般函数的地址没有区别,就是函数代码在内存中的真实地址,但其调用要绑定到一个实实在在的对象上。取其地址需要使用“&”运算符。
**virtual成员函数:**其地址指的是其在vtable中的位置;取其地址需要使用“&”运算符。
inline成员函数:在运行时会展开,虽然语言允许取其地址,但是没有太大意义。
static成员函数:其地址和普通全局函数的地址没有任何区别;其不依赖与类的对象而存在,也不依赖与类的对象而调用,只是作用域变成了类作用域,可以像取全局函数的地址那样直接把类静态成员函数名指派给一个普通全局函数类型的指针,并可以直接用这个指针实现对该静态成员函数的调用。

我们本文暂时只讨论普通成员函数和虚成员函数在调用过程中的区别。

讲解用例代码文章末。

调用默认的构造函数

首先因为含有虚函数的类,如果没有构造函数的话,也会调用默认的构造函数。
因为构造函数需要用来初始化虚表指针。(这也是构造函数为什么不可以作为虚函数的原因)。
在这里插入图片描述
从汇编角度看虚函数和普通成员函数的调用过程_第1张图片
虚表地址
从汇编角度看虚函数和普通成员函数的调用过程_第2张图片

一、普通成员函数

	A a;
	a.normaltest();  //调用普通成员函数

调用普通的成员函数。
直接根据函数地址进行跳转。从内存分布上也是地址也是比较随机的。
在这里插入图片描述

二、虚成员函数

可以看到虚表中只放了一个函数的地址,也就是虚函数Virtualtest()的地址。
从汇编角度看虚函数和普通成员函数的调用过程_第3张图片
所以说虚函数的调用,是先根据虚表指针找到虚表,然后根据虚表中函数地址进行调用。
在这里插入图片描述

#include
#include
using namespace std;


class A {
public:
	virtual void virtualtest() 
	{
		printf("Virtual\r\n");
	}
	void normaltest()
	{
		printf("Normal\r\n");
	}
};


void main()
{
	
	A a;
	a.normaltest();  //调用普通成员函数
	a.virtualtest(); //调用虚函数


	getchar();
}

你可能感兴趣的:(汇编)