《C++中类对象的内存布局和占用空间》 很多C++书籍中都介绍过,一个Class对象需要占用多大的内存空间。最权威的结论是: *加上编译器为了CPU计算,作出的数据对齐处理。 *加上为了支持虚函数,产生的额外负担。 介绍完了理论知识后,再看看再找一个例子看看(注:一下所有结果都是在VC6.0 开发环境中得出的结论) 一、空类的Size class Car { }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:1 这是为何呢?我想对于这个问题,不仅是刚入行不久的开发新手,就算有过几年以上C++开发经验的开发人员也未必能说清楚这个。 编译器在执行Car objCar;这行代码后需要,作出一个Class Car的Object。并且这个Object的地址还是独一无二的,于是编译器就会给空类创建一个隐含的一个字节的空间。 二、只有成员变量的Size class Car { private: int nLength; int nWidth; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:8 这个结果很多开发人员都清楚。在32位系统中,整型变量占4个字节。这里Class Car中含有两个整型类型的成员变量,所以Class Size是8。 class Car { private: int nLength; int nWidth; static int sHigh; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:8 我们这次在Class Car中添加了一个静态成员变量,但是Class Size仍然是8个字节。这正好符合了,结论中的第一条:非静态成员变量总合。 class Car { private: char chLogo int nLength; int nWidth; static int sHigh; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:12 在类中又插入了一个字符型变量,结果Class Size变成了12。这个就是编译器额外添加3个字符变量,做数据对齐处理,为了是提高CPU的计算速度。编译器额外添加的东西我们是无法看见的。这也符合了结论中的第二条:加上编译器为了CPU计算,作出的数据对齐处理。 既然,我们这样定义类成员数据编译器会额外的增加空。那么,我们何不在定义类的时候就考虑到数据对齐的问题,可以多定义出3个字符类型变量作为预留变量,既能满足数据对齐的要求,也给自己的程序添加了一些可扩展的空间。 三、只有成员函数的Size class Car { public: Car(){}; ~Car(){}; public: void Fun(){}; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:1 噢,这是怎么回事儿呢?再做一个实验看看。 class Car { public: Car(){}; ~Car(){}; public: void Fun(){}; private: int nLength; int nWidth; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:8 这次应该很清楚的了。函数是不占用类空间的。第一个例子中的Size为1个字节,正是编译器为类创建一个隐含的一个字节的空间 class Car { public: Car(){}; virtual ~Car(){}; public: void Fun(){}; }; void main() { int size = 0; Car objCar; size = sizeof(objCar); printf("%s %d /r", "Class Car Size:", size); } 输出结果:Class Car Size:4 这次,让析构函数为虚函数,看到了Class Size为4。这正是指向Virtual Table的指针vptr的Size。这正好符合了,结论中的第三条:加上为了支持虚函数,产生的额外负担。 到此为止,一个Class Object究竟占用多少内存空间,已经完全说清楚了。但是,这只是针对单独类,或者说是基类适用。对于子类,却不一样了。有兴趣的朋友可以做一些实验。
《C++ 类里面,函数占用存储空间问题 》 先看两段代码: 对象的大小是它的数据成员所占存储空间之和,就和结构体一样。类中的函数是所有该类对象通用的方法,不算作对象的成员,因此也不算在对象的存储空间内 问题:类里面不管有多少个函数,这个类的对象只占1个字节的内存。这个字节的内存的内容是什么?是指针吗?指针不是占4个字节吗? 当类中类有定义任何变量的时候,类的对象都是1个字节的,当类中没有任何变量的时候,这个类里没有任何真正的成员变量,所以大小应该是0,但0大小不好在内存中定位一个地址,所以,就规定它大小为0的对象要占一字节空间,以便让它拥有一个合法的地址。如果是有派生类的,还有考虑到内存对齐的问题的。
另外涉及到虚函数的话又不一样了。如 class A 原因是涉及到虚函数的实现问题。 class Class1 { m_data1; m_data2; virtual vfunc1() virtual vfunc2() virtual vfunc3() };
所以回到原来的问题,A中只有一个或者几个虚函数的话,没有成员变量,那么类A相当于含有一个vptr指向虚函数表的指针,所以sizeof(A)=4。 还有一点,如 class B { }; class B2 { }; class C:public B { }; class D:public virtual B { }; class E:public B,public B2 { }; sizeof(B) = 1; sizeof(B2) = 1; sizeof(C) = 1; sizeof(D) = 4; sizeof(E) = 1; 空类所占空间为一(上文以解释),单一继承的空类空间也是1,多重继承的空类空间还是1,但是虚继承涉及到虚表(虚指针),所以sizeof(D)=4。 |
|