今天闲来无事,研究起C++的内存布局来。得到几个结论,记录一下。
参考文献:http://haoel.blog.51cto.com/313033/124567(参考文献里面涉及的东西,这里都不再罗嗦。这里对文献做一点点补充。)
先看看几个类的实现。
class Base
{
public :
virtual void f()
{
cout<<"Base:f()"<<endl;
}
};
class Child :public Base
{
public:
virtual void f()
{
cout<<"child:f()"<<endl;
}
};
class B: public Child{
public :
int data;
virtual void f()
{
cout<<"B:f()"<<endl;
}
void h()
{
cout<<"B:h()"<<endl;
}
};
这里实现了3个类。一个基类Base,子类child,孙类B。这三个类都实现了虚函数f()。孙类有数据域data。为了方便使用,就public了。main函数实现如下:
void main(int argc, char* argv[])
{
B b;
B bb;
b.data=100;
cout<<*(((int*)&b)+1)<<endl;//间接访问数据域data
cout<<*(int*)(&bb)<<endl;//获取B类的虚拟函数表
cout<<*(int*)(&b)<<endl;//从另外一个对象中获取虚拟函数表的地址
b.f(); b.h();
b.B::f();//验证:每个类一个虚拟函数表
b.Child::f();
b.Base::f();
}
运行结果如下:
100
4649028
4649028
B:f()
B:h()
B:f()
child:f()
Base:f()
Press any key to continue
结论:
1.类的概念,只存在于编译时期。在代码运行时期,没有类,只有对象。
2.在单继承的情况,每个类有一个虚拟函数表,子类继承父类,只是拷贝父类的虚拟函数表,并不会修改父类的任何东西。最后几行的输出可证明。
3.一个具体的类只有一个虚拟函数表,它不属于任何对象。也就是说同一类的对象的虚拟跳转表的地址是一样的。第二行和第三行输出可以证明这个论点。
4.对于一个类,里面的虚拟函数,非虚拟函数,静态成员变量不占对象的空间。真正占用对象空间的只有数据域。也就是说,无论一个类有多少成员函数,这个类的对象的size不受影响。因为,成员函数只是存在于内存的代码段,而且所有相同类的对象共用相同的成员函数。
为了验证上面的结论,再举一个简单的好玩的例子。不用new,用结构体自己“new”一个对象出来。
定义一个类A:
class A
{
int a;
public:
virtual void f()
{
cout<<"A:f()"<<endl;
}
void show()
{
cout<<"A:a="<<a<<endl;
}
};
很简单吧?
然后定义一个结构体:
typedef struct
{
int fun;
int data;
} MyClass;
定义自己的“伪类”。fun表示虚拟跳转表,data是数据域。
void main(int argc, char* argv[])
{
MyClass cl;
cl.data=1000;//初始化数据
//下面三行是为了初始化虚拟函数调整表
A * a=new A();
cl.fun=*(int*)(a);
delete a;
//“骗”计算机用A类的形式访问结构体cl。
A* testA=(A*)&cl;
//测试
testA->f();
testA->show();
}
运行结果:
A:f()
A:a=1000
Press any key to continue