【C++】多态 ⑧ ( 验证指向 虚函数表 的 vptr 指针 | 对比定义了虚函数的类和没有定义虚函数类的大小 )

2023-11-01 09:21:16 浏览数 (1)

对比 定义了 虚函数 的类 与 没有定义虚函数的类 的大小 , 其它成员都相同 , 定义了虚函数的类多出了 4 字节 , 多出的 4 字节就是 vptr 指针占用的内存空间 ;

一、验证指向 虚函数表 的 vptr 指针 是否存在

1、虚函数表与 vptr 指针由来

" 虚函数表 " 由 C 编译器 负责 创建 与 维护 , 被 virtual 关键字 修饰的 虚函数 , 会自动 被 C 编译器 存储到 " 虚函数表 " 中 ;

虚函数表 创建 : 在 类 中使用 virtual 关键字 声明 虚函数 时 , C 编译器 会自动为该类生成 " 虚函数表 " ;

  • 生成虚函数表的前提是 至少有 1 个虚函数 ;
  • 如果 没有虚函数 , 就不会生成虚函数表 ;
  • 如果 类 中有 virtual 虚函数 , 则 该类的 每个对象 中 , 都有一个 指向 虚函数表的 vptr 指针 ;

虚函数表 存储 虚函数指针 : " 虚函数表 " 是 存储 " 类成员函数指针 " 的 数据结构 , 是一个 函数指针数组 , 数组中的元素都是函数指针 , 具体存储的都是 指向 类中的虚函数 的指针 ;

  • 如果 子类 中 , 重写了 父类的 virtual 虚函数 , 那么 C 编译器会在 子类 虚函数表 中放入该 子类虚函数的 函数指针 ;

如果 C 类中存在 virtual 虚函数 , 在创建对象时 , 会生成 虚函数表 Virtual Function Table , 简称 vtable ;

C 编译器 编译 代码时 , 会自动为该类 添加 一个 vptr 指针 成员变量 , 该指针 会指向 虚函数表 ;

2、虚函数类与普通函数类对比 - 多出了 vptr 指针的大小

下面的代码中 , 定义了 2 个类 , 区别是 一个定义了 virtual 虚函数 , 另外一个没有定义 虚函数 ;

  • 在 Parent 中定义了 虚函数 virtual void fun(int a) ;
  • 在 Parent2 中定义的是 普通函数 void fun(int a) ;

使用 sizeof 函数 , 获取这两个类的大小 , 判断两个类的区别 ;

最终得到 , 有 虚函数 的 类 , 比 没有 虚函数 的 类 , 多 4 字节 , 也就是一个指针的大小 ,

定义了 虚函数 的类 , 多出的 4 字节就是 vptr 指针的大小 ;

代码示例 :

代码语言:javascript复制
#include "iostream"
using namespace std;

// 父类
class Parent {
public:
	virtual void fun(int a)
	{
		cout << "执行 父类 Parent 的 virtual void fun(int a) 函数" << endl;
	}
	int a;
};

// 父类
class Parent2 {
public:
	void fun(int a)
	{
		cout << "执行 父类 Parent2 的 void fun(int a) 函数" << endl;
	}
	int a;
};

// 子类
class Child : public Parent {
public:
	virtual void fun(int a)
	{
		cout << "执行 子类 virtual void fun(int a) 函数" << endl;
	}
};

int main() {

	Parent* p;
	// 创建 Child 子类对象时
	// 发现有 virtual 虚函数 会创建 虚函数表
	// 在对象中使用 vptr 指针指向 虚函数表 首地址
	Child c;

	// 将父类指针指向子类对象
	p = &c;
	// 通过父类指针调用子类对象的 fun 函数
	p->fun(1);

	// 打印 Parent 的 大小
	cout << "sizeof(Parent) : " << sizeof(Parent) << endl;

	// 打印 Parent2 的 大小
	cout << "sizeof(Parent2) : " << sizeof(Parent2) << endl;

	// 控制台暂停 , 按任意键继续向后执行
	system("pause");

	return 0;
}

执行结果 :

执行 子类 virtual void fun(int a) 函数 sizeof(Parent) : 8 sizeof(Parent2) : 4 Press any key to continue . . .

0 人点赞