1、简单模型
1.1、概述
C++类中有两种数据成员:static、nonstatic;三种成员函数:static、nonstatic、virtual。它们在内存中的布局方式和访问方式是不同的。像nonstatic对象是在类对象内存储,虚函数是通过一个虚表指针指向一个虚表再通过虚表查找。静态和非静态函数都在对象之外存储。
1.2、对象模型图例
定义一个C++类:
class Base
{
public:
Base(int);
virtual ~Base(void);
virtual void base_print() const;
static void baseStaticFunc();
void baseNonStaticFunc();
protected:
int iBase;
static int iSatic;
};
Base类中各种成员如下图方式存储、访问:
不同编译存储各个成员可能有所差异,这是在Windows+VS2012中的布局。
可以看出Base对象中第一项是虚表指针,这个指针指向一张虚表,虚表中存储的是Base类各个虚函数的存储地址。在紧邻虚表的前一个位置是一个typeinfoPtr指针,它指向的是Base类的type_info信息。Base类的静态和非静态成员函数,静态成员数据在Base对象外存储。
1.3、验证模型
以下代码验证1.2图中模型:
void Base_Model()
{
cout << "********************Base b Model********************" << endl;
Base b(3);
cout << "对象b的内存地址 &b = " << &b << endl;
cout << "对象b中第一项 _vptr Base 虚表指针的值也即虚表首地址 = " << hex << *(int*)(&b) << endl;
cout << "对象b中第二项 int Base::iBase的值 = " << hex << *((int*)(&b) + 1) << endl;
cout << "虚函数表中第一个slot的值也即虚函数Base::~Base()的入口地址 = " << hex << *(int*)(*(int*)(&b)) << endl;
cout << "虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&b)) + 1) << endl;
pFun pBasePrint = (pFun)(*((int*)(*(int*)(&b)) + 1));
pBasePrint(); //注意这里输出是不一样的,这个调用仅仅是调用那段代码但是里面的iBase值不确定,因为iBase在Base对象中
b.base_print();
cout << "typeinfoPtr指针的存储位置 = " << ((*(int*)(&b)) - 1) << endl;
cout << "typeinfoPtr指针的值也即Base's type_info的首地址 = " << hex << *((int*)(*(int*)(&b)) - 1) << endl;
// cout << hex << Base::baseStaticFunc << endl;
// cout << hex << Base::baseStaticFunc2 << endl;
// cout << hex << &Base::baseNonStaticFunc << endl;
// typedef void (Base::*pmf)();
// pmf pt = &Base::baseNonStaticFunc;
// cout << hex << pt << endl;
}
运行结果:
2、对象模型with单继承
2.1、无重写单继承
无重写指的是派生类没有重写基类的虚函数。定义一个Base的派生类(除析构函数外无重写):
class Derived : public Base
{
public:
Derived(int);
virtual ~Derived(void);
virtual void derived_print(void);
protected:
int iDerived;
};
则派生类Derived及对象的布局方式如下图:
可以看到父类的虚函数放在了虚函数表的前面,后面放的是子类新加入的虚函数,子类的虚析构函数覆盖了父类的虚析构函数。
验证模型:
void DerivedInheritBase()
{
cout << "********************Derived d Model********************" << endl;
Derived d(6);
cout << "对象d的内存地址 &d = " << &d << endl;
cout << "对象d中第一项 _vptr Derived 虚表指针的值也即虚表首地址 = " << hex << *(int*)(&d) << endl;
cout << "对象d中第二项 int Base::iBase的值 = " << hex << *((int*)(&d) + 1) << endl;
cout << "对象d中第三项 int Derived::iDerived的值 = " << hex << *((int*)(&d) + 2) << endl;
cout << "虚函数表中第一个slot的值也即虚函数Derived::~Derived()的入口地址 = " << hex << *(int*)(*(int*)(&d)) << endl;
cout << "虚函数表中第二个slot的值也即虚函数Base::base_print()的入口地址 = " << hex << *((int*)(*(int*)(&d)) + 1) << endl;
cout << "虚函数表中第二个slot的值也即虚函数Derived::derived_print()的入口地址 = " << hex << *((int*)(*(int*)(&d)) + 2) << endl;
pFun pBasePrint = (pFun)(*((int*)(*(int*)(&d)) + 1));
pBasePrint();
d.base_print();
pFun pDerivdPrint = (pFun)(*((int*)(*(int*)(&d)) + 2));
pDerivdPrint();
d.derived_print();
cout << "typeinfoPtr指针的存储位置 = " << ((*(int*)(&d)) - 1) << endl;
cout << "typeinfoPtr指针的值也即Derived's type_info的首地址 = " << hex &l