- virtual关键字标识虚函数。
- 在C++中,使用基类的引用或指针调用一个虚函数是,发生动态绑定(或称运行时绑定)。
目录
结论三:vptr(虚表指针)是nonstatic 数据成员。
1、对象内部成员验证
根据C++对象模型的描述,nonstatic 数据成员存放在对象的内部。static 数据成员、nonstatic和static函数成员存放在对象的外部。
测试代码一:
#include <iostream>
using namespace std;
class Base
{
public:
static int getGlobal(); //static 函数成员
void setData(const int data); //nonstatic函数成员
int getDate()const; //nonstatic 函数成员
private:
static int g_global; //static 数据成员
int m_data; //nonstatic 数据成员
};
int Base::g_global = 0;
int main()
{
Base bs; //定义一个对象
bs.setData(12);
int Base_size = sizeof(bs);//查看对象(bs)占用内存大小
return 0;
}
调试结果:
![](https://i-blog.csdnimg.cn/blog_migrate/9eaa30004d209947ec6c31c8e120a025.png)
分析:
从图1调试结果可以看出,对象(bs)的内存占用大小只包含了nonstatic 数据成员(m_data)。
结论一:对象内部存放的是nonstatic 数据成员。
2.虚表指针验证
虚函数的实现有2部分构成:
1).每个类产生一堆虚函数的指针,存放在虚函数表中(virtual table, vtbl)
2).每个对象有一个指向vtbl的指针(vptr)。vptr的设置和重置由每个类的构造函数,析构函数和拷贝赋值运算符自动完成。
测试代码二:
class Base
{
public:
static int getGlobal();
virtual void show(); //虚函数
void setData(const int data);
int getDate()const;
private:
static int g_global;
int m_data;
};
//==============================================
main.c:
int main()
{
1: Base bs;
2: bs.setData(12);
3: int Base_size = sizeof(bs);
return 0;
}
调试结果:
![](https://i-blog.csdnimg.cn/blog_migrate/f4832a86fd2bc87f15d893f5a90158ce.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5ddf3ef0d0aee1983b85fb6a5cdf52ec.png)
单步调试发现:当执行1指令后,虚表指针内容发生改变。
结论二:vptr(虚表指针)的初始化是由构造函数完成的。
![](https://i-blog.csdnimg.cn/blog_migrate/29e39091ebdb119e21c0b58d434b6478.png)
分析:图2-3显示 对象(bs)内存大小为8。测试代码相较测试一,多了一个虚函数(void show())。对应的调试结果中多了_vptr.Base变量。根据结论一推出,_vptr.Base是一个nonstatic 数据成员。
结论三:vptr(虚表指针)是nonstatic 数据成员。
3.对虚函数存放位置验证。
测试代码三:
class Base
{
public:
static int getGlobal();
virtual void show();
virtual void show1();
void setData(const int data);
int getDate()const;
private:
static int g_global;
int m_data;
};
//================================================================
int main()
{
Base bs;
bs.setData(12);
bs.show();
void (Base::*p1)() = &Base::show; //定义函数指针(p1),获取虚函数(show)地址
void (Base::*p2)() = &Base::show1; //定义函数指针(p2), 获取虚函数(show1)地址
int Base_size = sizeof(bs);
return 0;
}
调试显示:
![](https://i-blog.csdnimg.cn/blog_migrate/c2872eeb5bc5e1dd841037fc7c9670f4.png)
分析:从调试结果看,函数指针获取的地址是,虚函数在virtual table(虚函数表) 中的偏移位置。并且大小为4字节,所以推出结论4.
结论四:虚函数表中存放的是函数指针(指向虚函数)。
![](https://i-blog.csdnimg.cn/blog_migrate/73a92de6f1922363f6d5798430104d04.png)
相关参考资料:
[1] C++语言知识点汇总
[2] 何为C++对象模型?