多态 虚函数表深度剖析 纯干货讲解(2)

博客内容:多态

作  者:陈大大陈

个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!

欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信

目录

虚函数存在哪里? 

虚函数的地址一定会被放进虚函数表吗?

结论 


 

虚函数储存在哪里? 

 首先思考一个问题,虚函数存在哪里?

虚函数和普通函数一样,存在代码段,同时将虚函数地址存了一份到虚函数表。

那虚函数表存在哪里?

存在栈区出了作用域会销毁,堆区需要动态分配内存,都不现实。

经过测试,虚表是储存在常量区的代码段的,跟常量很接近。

虚函数的地址一定会被放进虚函数表吗?

第二个问题,虚函数的地址一定会被放进虚函数表吗?

#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

int main()
{
	Base b;
	Derive d;
	X x;

	Derive* p = &d;
	p->func3();

	p = &x;
	p->func3();

	return 0;
}

多态 虚函数表深度剖析 纯干货讲解(2)_第1张图片

如图,这种情况三个虚表指针都没有存储func3的地址。 

难道是func3的地址没有存储吗?
并不是这样,监视窗口看到的内容是经过编译器处理的。

我们合理怀疑编译器骗我们。

多态 虚函数表深度剖析 纯干货讲解(2)_第2张图片

打开内存监视窗口,我们高度怀疑后面两个地址是被隐藏的两个虚函数的地址。 

虚表储存在类的前四个字节,我们就取这四个字节打印出来。

typedef void (*VFUNC) ();
void PrintVFT(VFUNC a[])
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p\n", i, a[i]);
	}
	cout << endl;
}
int main()
{
	//void (*f)();
	VFUNC f2;
	Base b;
	PrintVFT((VFUNC*)(*((int*)&b)));
	return 0;
}

多态 虚函数表深度剖析 纯干货讲解(2)_第3张图片

看不明白的老铁可以看看上面的图。 

传入base类打印,结果如下。

多态 虚函数表深度剖析 纯干货讲解(2)_第4张图片

不对劲,清理解决方案之后再重新生成解决方案,再次编译。

 多态 虚函数表深度剖析 纯干货讲解(2)_第5张图片

第一次编译器出了bug,没有在虚表后标识上0,第二次就好了。 

多态 虚函数表深度剖析 纯干货讲解(2)_第6张图片

比葫芦画瓢打印一下d和x,但是此时仍然不能确定。 

终于到了放终结技的时候了,我们可以在打印的时候同时调用函数。

上面我们埋下了伏笔,在命令行窗口会打印出来调用函数的信息。

#define _CRT_SECURE_NO_WARNINGS
#include
using namespace std;
class Base {
public:
	virtual void func1() { cout << "Base::func1" << endl; }
	virtual void func2() { cout << "Base::func2" << endl; }
private:
	int a;
};

class Derive :public Base {
public:
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func3" << endl; }
	virtual void func4() { cout << "Derive::func4" << endl; }
	void func5() { cout << "Derive::func5" << endl; }
private:
	int b;
};

class X :public Derive {
public:
	virtual void func3() { cout << "X::func3" << endl; }
};

//int main()
//{
//	Base b;
//	Derive d;
//	X x;
//
//	Derive* p = &d;
//	p->func3();
//
//	p = &x;
//	p->func3();
//
//	return 0;
//}
typedef void (*VFUNC) ();
void PrintVFT(VFUNC *a)
{
	for (size_t i = 0; a[i] != 0; i++)
	{
		printf("[%d]:%p\n", i, a[i]);
		VFUNC f = a[i];
		f();
	}
	cout << endl;
}
int main()
{
	//void (*f)();
	VFUNC f2;
	Base b;
	Derive d;
	X x;
	PrintVFT((VFUNC*)(*((int*)&b)));
	PrintVFT((VFUNC*)(*((int*)&d)));
	PrintVFT((VFUNC*)(*((int*)&x)));
	return 0;
}

运行结果如下。

多态 虚函数表深度剖析 纯干货讲解(2)_第7张图片

结论 

可算对上了捏!

 此时此刻,我们终于可以骄傲地回答上面的问题!

所有的虚函数都会被放进虚表吗?

是的!

你可能感兴趣的:(C语言初阶以及进阶内容专栏,jvm,c++,开发语言,算法,数据结构,c语言)