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:俗称 函数指针)

相关推荐
许长安27 分钟前
RPC 同步调用基本使用方法:基于官方 RouteGuide 示例
c++·经验分享·笔记·rpc
kyriewen1138 分钟前
WebAssembly:前端界的“外挂”,让C++代码在浏览器里跑起来
开发语言·前端·javascript·c++·单元测试·ecmascript
浅念-4 小时前
刷穿LeetCode:BFS 解决 Flood Fill 算法
数据结构·c++·算法·leetcode·职场和发展·bfs·宽度优先
做cv的小昊4 小时前
【TJU】研究生应用统计学课程笔记(8)——第四章 线性模型(4.1 一元线性回归分析)
笔记·线性代数·算法·数学建模·回归·线性回归·概率论
楼田莉子5 小时前
Linux网络:NAT_代理
linux·运维·服务器·开发语言·c++·后端
我命由我123455 小时前
程序员的心理学学习笔记 - 空杯心态
经验分享·笔记·学习·职场和发展·求职招聘·职场发展·学习方法
南境十里·墨染春水5 小时前
C++日志 2——实现单线程日志系统
java·jvm·c++
stm32 菜鸟5 小时前
nucleo-f411re学习记录-13,flash的操作
学习
zh_xuan5 小时前
api测试工具添加历史记录功能
c++·libcurl·duilib
晓梦林5 小时前
3170靶场学习笔记
笔记·学习