C++_虚函数表

虚函数表

介绍

1.编译器通过指针或引用调用虚函数,不会立即生成函数调用指令,而是用 二级函数指针 代替

1.1确定真实类型

1.2找到虚函数表从而找到入口地址

1.3根据入口地址调用函数(PS:俗称 函数指针)

** 虚函数表 内部存储格式展示**

代码图详解

源码

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

class N
{
public:
	void foo()
	{
		cout << "N::foo" << endl;
	}
	void ber()
	{
		cout << "N::ber" << endl;
	}
	int m_a;
	int m_b;
};
class A
{
public:
	virtual void foo()
	{
		cout << "A::foo" << endl;
	}
	virtual void ber()
	{
		cout << "A::ber" << endl;
	}
	double m_a;
	int m_b;
};
class B:public A
{
public:
	void foo()
	{
		cout << "B::foo" << endl;
	}
	void ber()
	{
		cout << "B::ber" << endl;
	}
};
void main()
{
	A a;//在A类型中会多生成一个最大类型的 字节指针(内部存储的是函数指针)
	B b;//在B类型中会多生成一个最大类型的 字节指针(内部存储的是函数指针)
	A*pa = &b;

	//获取 N 类型大小
	cout << "sizeof(N):" << sizeof(N);
	//获取 N 相对于 m_a 的距离
	cout << ",m_a:" << offsetof(N, m_a);
	//获取 N 相对于 m_b 的距离
	cout << ",m_b:" << offsetof(N, m_b) << endl;

	//获取 A 类型大小
	cout << "sizeof(N):" << sizeof(A);
	//获取 A 相对于 m_a 的距离
	cout << ",m_a:" << offsetof(A, m_a);
	//获取 A 相对于 m_b 的距离
	cout << ",m_b:" << offsetof(A, m_b) << endl;
	cout << "-------------------分隔符-------------------" << endl;
//函数指针调用函数
	
	void *vf_ptr = *(void**)&a; //获取 A类型 中 a 地址
	cout <<"A类型 中 a 地址为:"<< vf_ptr << endl;    //打印 A类型 中 a 地址
	cout << "-------------------分隔符-------------------" << endl;
	//取别名
	typedef void(*VFUN)(void*); //VFUN 相当于 void(*)  // *VFUN 函数指针类型
	typedef VFUN* VPTR;         //VPTR 相当于 void(**) //指向函数指针类型的指针 VPTR虚函数表类型
	VPTR _vfptr = *(VPTR*)&a;   //获取 A类型 中 a 地址
	cout << "A类型 中 a 地址为:" << _vfptr << endl;   //打印 A类型 中 a 地址
	a.foo();                    //正常调用方法
	_vfptr[0](&a);              //编译器中调用方法 结果为:A::foo
	_vfptr[1](&a);              //编译器中调用方法 结果为:A::ber

	cout << "-------------------分隔符-------------------" << endl;
	VPTR _vfptr1 = *(VPTR*)&b;   //获取 B类型 中 b 地址
	cout << "B类型 中 b 地址为:" << _vfptr1 << endl;   //打印 B类型 中 b 地址
	b.foo();                    //正常调用方法
	_vfptr1[0](&b);              //编译器中调用方法 结果为:B::foo
	_vfptr1[1](&b);              //编译器中调用方法 结果为:B::ber

	system("pause");
}

运行结果

cpp 复制代码
sizeof(N):8,m_a:0,m_b:4
sizeof(N):24,m_a:8,m_b:16
-------------------分隔符-------------------
A类型 中 a 地址为:0015DC80
-------------------分隔符-------------------
A类型 中 a 地址为:0015DC80
A::foo
A::foo
A::ber
-------------------分隔符-------------------
B类型 中 b 地址为:0015DCA0
B::foo
B::foo
B::ber
请按任意键继续. . .

笔记扩充

void(VFUN)(void) 的代码解释,参考下列源码

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

//构造3个通用函数
void TEST1(void) { printf("test1\n"); }//函数定义  
void TEST2(void) { printf("test2\n"); }//函数定义  
void TEST3(void) { printf("test3\n"); }//函数定义  
//声明(取别名为:(*func)函数)是 void 类型
typedef void(*func)(void);

void test(int i)
{
	func vTask[3] = { &TEST1, &TEST2, &TEST3 };//func 类型代替 void功能
	func fun = vTask[i];//将vTask函数赋值到fun中
	(*fun)();//调用(*fun) ()函数
}
void main()
{
	test(0);
	test(1);
	test(2);
	system("pause");
}

函数名联编

将源代码中的函数调用解释为执行特定的函数代码块被称为 函数名联编

静态联编

1.静态联编是指 联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的, 又称为:早期联编

2.静态联编对函数的选择是基于指向对象的指针或者引用的类型

3.优点是效率高,灵活性差

4.静态联编是根据 所定义的类 来调用 类中函数(PS:相当于直接调用当前类代码,不会做任何检查)

动态联编

1.动态联编 是指联编在程序运行时动态地进行,这种联编又称为晚期联编。或动态束定

2.动态联编对成员函数的选择是基于对象的类型

3.优点是灵活性强,效率低

4.实际上是在运行时虚函数(virtual)的实现。(PS:先进行检查后,根据当时的情况来确定调用哪个同名函数)
动态联编 调用步骤:

1.1确定真实类型

1.2找到虚函数表从而找到入口地址

1.3根据入口地址调用函数(PS:俗称 函数指针)

相关推荐
渡我白衣41 分钟前
字符串的陷阱与艺术——std::string全解析
网络·c++·人工智能·自然语言处理·智能路由器·信息与通信·caffe
吃不饱的得可可1 小时前
C++17常用新特性
开发语言·c++
谅望者1 小时前
数据分析笔记02:数值方法
大数据·数据库·笔记·数据挖掘·数据分析
_OP_CHEN1 小时前
算法基础篇:(七)基础算法之二分算法 —— 从 “猜数字” 到 “解难题” 的高效思维
c++·算法·蓝桥杯·二分查找·acm·二分答案·二分算法
IT19951 小时前
Wireshark笔记-DNS流程与数据包解析
笔记·测试工具·wireshark
一匹电信狗1 小时前
【C++11】Lambda表达式+新的类功能
服务器·c++·算法·leetcode·小程序·stl·visual studio
say_fall1 小时前
C语言编程实战:每日刷题 - day 1
c语言·开发语言·学习
小苏兮1 小时前
【把Linux“聊”明白】进程的概念与状态
linux·运维·服务器·学习
♛小小小让让1 小时前
python logging模块:专业日志记录
笔记·python
煤球王子1 小时前
学而时习之:C++中的枚举
c++