深入了解C++ 结构体(struct)与共用体(union)
结构体struct与共用体union是C语言中就已经存在的数据类型C对他们进行了扩充最大的变化是允许在结构和公用体中定义成员函数。下面将通过实例讲解二者的特性和用法。1.struct以下是一个使用了结构体的C程序。12345678910111213141516171819202122232425262728293031#include iostreamusingnamespacestd;structRoom{intfloor;intNo;};structStudent{intage;intscore;Student(inta,ints){agea;scores;}};intmain(intargc,char* argv[]){Room r[3]{{1,101},{2,201},{3,301}};Student s(18,89);coutthe room are:;coutr[0].floor-r[0].No ;coutr[1].floor-r[1].No ;coutr[2].floor-r[2].Noendl;coutthe students age:s.age score:s.scoreendl;getchar();}程序运行结果the room are:1-101 2-201 3-301the students age:18 score:89阅读以上程序在C中使用结构体需要注意以下几点1C中结构体是一种真正的数据类型在利用结构定义变量时不需要像在C中带上struct关键字或先使用typedef struct structname structalias的方式进行申明。2C对C中的struct进行了扩充允许在struct中定义成员函数。struct中的成员变量和成员函数也有访问权限在class中默认的访问权限是private而在struct中默认访问权限是public这是结构体和类的唯一区别。struct成员的默认访问权限设为public是C保持与C语言兼容而采取的一项策略。3如果struct中没有显示定义任何构造函数那么结构变量可以像在C语言中那样用花括号顺序指明数据成员的值来进行初始化。但是一旦显示定义了任何一个构造函数就不能用这种方式初始化了。如果在class中只有若干public型的数据成员而没有显示定义任何构造函数也可以使用花括号进行初始化。4用sizeof运算符计算结构的大小时要考虑结构体内部变量的对齐问题。2.union共用体union又名联合体是一种特殊的类从C语言章继承而来其基本语义没有发生什么变化只是具有了类的一些特性允许定义成员函数。在实际的编程实践中使用频率没有struct高。与struct相比最显著的区别是union的数据成员共享同一段内存以达到节省空间的目的。2.1union的基本性质通过如下程序考察union变量的占用空间成员赋值时的相互影响。12345678910111213141516171819202122232425#include iostreamusingnamespacestd;uniontestunion{charc;inti;};intmain(intargc,char* argv[]){coutsizeof(testunion)endl;testunion* ptnewtestunion;char* preinterpret_castchar*(pt);for(inti0;isizeof(*pt);i)coutint(p[i]) ;coutendl;coutpt-iendl;pt-cA;coutpt-cendl;for(inti0;isizeof(*pt);i)coutint(p[i]) ;coutendl;coutpt-iendl;deletept;}程序运行结果4-51 -51 -51 -51-842150451A65 -51 -51 -51-842150591可以看出union testunion变量的体积是4它是由两个数据成员中体积较大的一个int类型来决定的。对其中一个数据成员的修改一定会同时改变所有其他数据成员的值。不过对体积较小的数据成员的修改只会影响到该成员应该占用的那些字节对超出部分高位字节没有什么影响。2.2union的高级特性观察如下程序。123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869#include iostreamusingnamespacestd;structStudent{intage;intscore;Student(inta,ints){agea;scores;}};uniontestunion{charc;inti;};classsomeClass{intnum;public:voidshow(){coutnumendl;}};unionA{charc;inti;doubled;someClass s;};unionB{charc;inti;doubled;B(){d8.9;}};union{charc;inti;doubled;voidshow(){coutcendl;}}u{U};intmain(intargc,char* argv[]){A a{A};B b;couta.cendl;coutb.dendl;a.s.show();u.show();//匿名共用体union{intp;intq;};p3;coutqendl;}程序运行结果A8.965U3阅读以上程序需要注意以下几点1union可以指定成员的访问权限默认情况下与struct具有一样的权限public。2union也可以定义成员函数包括构造函数和析构函数。与struct不同的是它不能作为基类被继承。3union不能拥有静态数据成员或引用成员因为静态数据成员实际上并不是共用体的数据成员它无法和共用体的其它数据成员共享空间。对于引用变量引用本质上是一个指针常量它的值一旦初始化就不允许修改。如果共用体有引用成员那么共用体对象一创建初始化后就无法修改只能作为一个普通的引用使用这就失去了共用体存在的意义。4union允许其他类的对象成为自己的数据成员但是要求该类对象所属类不能定义constructorcopy constructordestructorassignment operatorvirtual function中的任意一个。因为4.1union数据成员共享内存union构造函数在执行的时候不能调用数据成员为类对象的构造函数否则就改变了其他数据成员的值。4.2同样union的对象成员的析构函数也不能被调用因为其他数据成员的值对于对象成员而言可能毫无意义。4.3union的对象成员的赋值应该维持其原始语义不建议进行赋值运算符的重载因为赋值运算符重载一般用于“深拷贝”等场合而在对象空间与其它变量共享的情况下“深拷贝”引入的内存资源指向内存资源的指针往往会被其它共用体数据成员修改导致内存资源无法寻址造成内存泄漏。此外因为union的对象成员没有自定义的析构函数也会导致内存泄漏。4.4拥有虚函数的类对象虚函数表指针可能会在共用体对象初始化时被覆盖导致无法寻址虚函数表所以也不能拥有虚函数。5如果union类型旨在定义该类的同时使用一次以后不再使用了那么也可以不给出union的名称。如上例中变量u就是这种情况这种情况下无法为该union定义构造函数。6匿名共用体Anonymous Union也就是给出一个不带名称的共用体的申明后并不定义任何该union的变量而是直接以分号结尾。严格来说匿名共用体并不是一种数据结构因为它不能用来定义共用体对象它只是指明若干个变量共享一片内存单元。在上例中对变量p的修改实际上修改了变量q。可以看出尽管匿名共用体中的变量被定义在同一个共用体中他们与同一个程序块的任何其他局部变量具有相同的作用域级别。这意味着匿名共用体内的成员的名称不能与同一个作用域内的其它标识符相冲突。另外对匿名共用体还存在如下限制6.1匿名共用体不允许有成员函数6.2匿名共用体也不能包含私有或者保护成员6.3全局匿名共用体中的成员必须是全局或静态变量。