基础
数据成员分类
static data members
编译器把static data members放在类的对象之外,即将唯一的实体在程序数据区中,当两个类中的static data members同名时,编译器会推导出独一无二的名字。
我们可以通过对象、指针、和类都可以取得static data members。
1 #include <iostream> 2 3 using namespace std; 4 5 class A{ 6 public: 7 static int stcMem; 8 int i = 10; 9 }; 10 11 int A::stcMem = 5; //初始化 12 int main() 13 { 14 A a; 15 A* p = &a; 16 cout << a.stcMem << endl; //通过对象取用 17 cout << p->stcMem << endl; //通过指针取用 18 cout << A::stcMem << endl; //通过类取用 19 20 return 0; 21 } 22 23
nonstatic data members
编译器将nonstatic data members整合在一起为类对象实体,C++并没有规定对象的nonstatic data member的布局顺序,顺需由不同的编译器自己决定。当我们取用nonstatic data members时,编译器会根据对象地址和成员偏移量来确定。
我们可以通过对象、指针、引用、和成员函数中的this指针取用nonstatic data members。
对象的内存布局
单继承
不要多态,即没有虚函数的情况:
加上多态:
多继承
虚继承
对象大小
一个class对象需要多少内存呢,一般是一下几点的和:
- nonstatic数据成员的大小之和;
- 加上由于对齐而产生的填补(与机器有关);
- 加上为了支持virtual而增加的额外负担(与编译器有关 )。
另外值得注意的是一个没有nonstatic的类的对象的大小是1,这是被编译器安插的一个char类型,为了让该类的每个对象具有独一无二的内存地址。
指向data members的指针
作用1:可以用来确定vptr是放在对象模型的首部还是尾部。不同的编译器vptr的位置不同,因为C++允许把vptr放在任何位置,通常会放在首部和尾部。
作用2:可以用来确定对象成员的布局次序。
&className::dataName 可以获得成员数据的对象中的偏移量,注意这个偏移量会被编译器加1,为了可以表示空数据类的成员指针。所以在取用对象的时候,&obj + (&className::dataName - 1)。
参考
《深度探索C++对象模型》