💯 博客内容:多态
😀 作 者:陈大大陈
🚀 个人简介:一个正在努力学技术的准C++后端工程师,专注基础和实战分享 ,欢迎私信!
💖 欢迎大家:这里是CSDN,我总结知识和写笔记的地方,喜欢的话请三连,有问题请私信 😘 😘 😘
目录
虚函数存在哪里?
虚函数的地址一定会被放进虚函数表吗?
结论
虚函数储存在哪里?
首先思考一个问题,虚函数存在哪里?
虚函数和普通函数一样,存在代码段,同时将虚函数地址存了一份到虚函数表。
那虚函数表存在哪里?
存在栈区出了作用域会销毁,堆区需要动态分配内存,都不现实。
经过测试,虚表是储存在常量区的代码段的,跟常量很接近。
虚函数的地址一定会被放进虚函数表吗?
第二个问题,虚函数的地址一定会被放进虚函数表吗?
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
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;
}
如图,这种情况三个虚表指针都没有存储func3的地址。
难道是func3的地址没有存储吗?
并不是这样,监视窗口看到的内容是经过编译器处理的。
我们合理怀疑编译器骗我们。
打开内存监视窗口,我们高度怀疑后面两个地址是被隐藏的两个虚函数的地址。
虚表储存在类的前四个字节,我们就取这四个字节打印出来。
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;
}
看不明白的老铁可以看看上面的图。
传入base类打印,结果如下。
不对劲,清理解决方案之后再重新生成解决方案,再次编译。
第一次编译器出了bug,没有在虚表后标识上0,第二次就好了。
比葫芦画瓢打印一下d和x,但是此时仍然不能确定。
终于到了放终结技的时候了,我们可以在打印的时候同时调用函数。
上面我们埋下了伏笔,在命令行窗口会打印出来调用函数的信息。
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
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;
}
运行结果如下。
结论
可算对上了捏!
此时此刻,我们终于可以骄傲地回答上面的问题!
所有的虚函数都会被放进虚表吗?
是的!