C++这方面的知识一直理解得不够深入,最近又复习了一下。把之前朋友教的,自己看的内容都整理出来,算是对这块知识点的总结了。
先看几个例子:
//默认为4字节对齐情况 //Example 1 struct A { char c; }; //Example 2 struct B { char c; int a; }; //Example 3 struct C { char c; char c2; int a; }; //Example 4 struct D { char c; int a; char c2; }; //Example 5 struct E { char c; short a; char c2; }; int main(int argc, char* argv[]) { cout<<"sizeof A:"<<sizeof(A)<<endl; cout<<"sizeof B:"<<sizeof(B)<<endl; cout<<"sizeof C:"<<sizeof(C)<<endl; cout<<"sizeof D:"<<sizeof(D)<<endl; cout<<"sizeof E:"<<sizeof(E)<<endl; return 0; } |
计算这些类型的sizeof的要点是了解下面几个概念。
1、当类中最大元素类型的大小小于编译器指定的对齐字节要求时。元素对齐以最大类型为准。如struct E,以2字节对齐,因为short类型为类元素中最大类型,它是2字节。
2、当类中最大元素类型的大小大于等于编译器指定的对齐字节要求时。元素对齐以编译器指定的对齐字节为准。如除struct E和struct A以外的其它struct都属于此情况。
3、在不单要保证元素对齐的情况下,也同时要保证结构对齐。如Struct D的情况,虽然char c2是最后一个元素,但也要padding三个字节。
然后增加一点难度:
//默认为4字节对齐情况 struct F { int i; double d; char c; int geti(){ return i;} virtual double getd(){return d;}; virtual char getcc(){return c;}; }; int main(int argc, char* argv[]) { cout<<"sizeof F:"<<sizeof(F)<<endl; //20 return 0; } |
此结构比之前多了虚函数与普通函数,这里的概念是:
1、C++为尽量的与C兼容,以便充分利用C语言的高效特性。所以C++的class/struct也被设计成尽量与C的struct模型一致。C++把class的成员函数都设计成与普通函数一致。那么成员函数与普通函数一点区别都没有吗?在C++中,成员函数被编译器自动多加了一个参数,这个参数就表示调用方的class实例。对于上面的例子,其中的geti可能会变成这样:_geti(const F* this);
2、为了实现多态,类中的虚函数会被记录在虚表指针中,为类的一个隐型成员。同时,再另外一个位置会生成跟这个类相对应的一个虚表,虚表的大小跟虚函数的个数相关。虚表中的每一项都指向一个函数体。
所以上例中,除了计算成员变量的大小外,普通成员函数的大小不用计算。另外因为有虚函数,所以在类中有一个隐型的指针。
现在如果有继承关系又会是如何呢?
//默认为4字节对齐情况 struct F { int i; double d; char c; int geti(){ return i;} virtual double getd(){return d;}; virtual char getcc(){return c;}; }; struct G : public F { int gi; }; struct H : public F { int gi; virtual char getgi(){return gi;}; }; int main(int argc, char* argv[]) { cout<<"sizeof F:"<<sizeof(F)<<endl; //20 cout<<"sizeof G:"<<sizeof(G)<<endl; //24 cout<<"sizeof H:"<<sizeof(H)<<endl; //24 return 0; } |
这里相对简单很多,对于G来说,因为其从F派生。所以它的大小就是F的大小,加上其新定义的元素大小之和。而H虽然也有自生的虚函数,但类派生后,虚表指针还是只有一个。所以其大小和一样。
特殊情况:
//默认为4字节对齐情况 struct I{}; int main(int argc, char* argv[]) { cout<<"sizeof I:"<<sizeof(I)<<endl; //结果与编译器相关 return 0; } |
这种情况下,其结果与使用的编译器相关,在VC下为1,在BCB下为4。
最后在网上看到过一个别人实现sizeof的例子,引用一下^_^。
#include<iostream> #include<conio.h> #include<stdio.h> using namespace std; #define getsize(x) ((char *)(&(x) + 1) - (char *)&(x)) //macros main() { char a[]="hello"; cout<<getsize(a); //output is 6 because backslash 0 has to be considered. getch(); return 0; } |
歌曲推荐:
〈The Answer Lies Within》
答案就在内心深处
Dream Theater
Look around Where do you belong
环顾四周 哪里才是你的容身之处
Don’t be afraid You’re not the only one
不要害怕 你不会总是独自上路
Don’t let the day go by
别让这光阴虚度
Don’t let it end
别让它就这样结束
Don’t let a day go by in doubt
别让又一天在疑问中虚度
The answer lies within
答案就在内心深处
Life is short So learn from your mistakes
生命如此短暂 所以该直面错误
And stand behind The choices that you make
既然做出选择 就无论如何坚持住
Face each day With both eyes open wide
睁大你的双眼 认真面对这每一天
And try to give Don’t keep it all inside
别再闭门自赏 尝试着学会付出
Don’t let the day go by
别让这光阴虚度
Don’t let it end
别让它就这样结束
Don’t let a day go by in doubt
别让又一天在疑问中虚度
The answer lies within
答案就在内心深处
You’ve got the future on your side
这漫长的人生道路上
You’re gonna be fine now
一个属于你的未来就在前方
I know whatever you decide
而我知道无论你决定怎样
You’re gonna shine
是金子就终究会闪光
Don’t let the day go by
别让这光阴虚度
Don’t let it end
别让它就这样结束
Don’t let a day go by in doubt
别让又一天在疑问中虚度
You’re ready to begin
你应该准备好上路
Don’t let a day go by in doubt
别让又一天在疑问中虚度
The answer lies within
答案就在内心深处