C++虚指针、虚表

C++多态

可分为静态多态和动态多态

  • 静态多态就是在系统编译期间就可以确定程序执行到这里将要执行哪个函数,例如函数重载
  • 动态多态则是利用虚函数实现,在系统编译的时候并不知道程序将要调用哪一个函数,只有在运行到这里的时候才能确定接下来会执行什么函数

重载比较简单这里就不说,今天我们主要来谈一谈虚函数

虚表和vptr指针

  • 当类中声明虚函数时,编译器会在类中生成一个函数虚表
  • 虚函数表是一个存储 类成员函数指针 的数据结构
  • 虚函数表是由编译器自动生成和维护的
  • virtual成员函数会被编译器放入虚函数表中
  • 存在虚函数时,每个对象中都有一个指向虚函数表的指针(vptr指针)

如何验证vptr指针存在?

先看如下代码,父亲类中没有声明虚函数,只有一个int成员,而子类中声明虚函数,并且拥有一个int成员

#include 
using namespace std;

class Father
{
public:
	int Fun1(int a);

private:
	int a;
};

class Child
{
public:
	virtual int Fun1(int a);

private:
	int a;
};

int main()
{
	int Father_test = sizeof(Father);
	int Child_test = sizeof(Child);
	cout << "Father_test = " << Father_test << endl;
	cout << "Child_test = " << Child_test << endl;

	while (1);
	return 0;
}

运行结果如下
在这里插入图片描述
子类中声明了虚函数,系统自动生成了一个vptr指针,其大小4字节;因此子类总大小为8字节。

虚表的解释之前看到一篇文章解释的比较清楚,文章会围绕四钟情况来进行解释,下面来自该文章的解释

1、在单继承没有覆盖的情况下,子类的虚表会紧跟父类的虚表(虚函数按照声明顺序放于表中)。

#include
using namespace std;
 
class Base
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Derive : public Base
{
	virtual void f1()
	{}
	virtual void g1()
	{}
	virtual void h1()
	{}
};
 
void main()
{
	Derive d;
}

C++虚指针、虚表_第1张图片
2、在单继承有覆盖的情况下,覆盖的子类会替代原先父类虚表的位置,其余的子类虚表会紧跟父类

class Base
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Derive : public Base
{
	virtual void f()
	{}
	virtual void g1()
	{}
	virtual void h1()
	{}
};
 
void main()
{
	Derive d;
}

C++虚指针、虚表_第2张图片
3、在多继承没有覆盖的情况下,子类的虚表会紧跟第一个父类的虚表,其他的父类虚表中不会出现子类的虚表

#include
using namespace std;
 
class Base
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Base1
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Base2
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Derive : public Base, public Base1, public Base2
{
	virtual void f1()
	{}
	virtual void g1()
	{}
	virtual void h1()
	{}
};
 
void main()
{
	Derive d;
}

C++虚指针、虚表_第3张图片
4、在多继承有覆盖的情况下,覆盖的子类会替代所有父类同名虚函数在虚表中的位置,其余的子类虚表会紧跟第一个父类的虚表

#include
using namespace std;
 
class Base
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Base1
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Base2
{
	virtual void f()
	{}
	virtual void g()
	{}
	virtual void h()
	{}
};
class Derive : public Base, public Base1, public Base2
{
	virtual void f()
	{}
	virtual void g1()
	{}
	virtual void h1()
	{}
};
 
void main()
{
	Derive d;
}

C++虚指针、虚表_第4张图片
基类的指针和引用调动派生类的虚函数,并不是访问的是派生类的虚函数,而是访问基类中被派生类覆盖的虚函数。所以访问的位置还是在基类中,并没有进入派生类,这也是多态的实质。
C++虚指针、虚表_第5张图片
该段落来自作者:zxx2096
原文:https://blog.csdn.net/zxx2096/article/details/80056705

你可能感兴趣的:(C/C++)