原文地址:http://ideage.javaeye.com/blog/210614

联合(union)在C/C++里面见得并不多,但是在一些对内存要求特别严格的地方,联合又是频繁出现,那么究竟什么是联合、怎么去用、有什么需要注意的地方呢?就这些问题,我试着做一些简单的回答,里面肯定还有不当的地方,欢迎指出!

1、什么是联合? 
   “联合”是一种特殊的类,也是一种构造类型的数据结构。 在一个“联合”内可以定义多种不同的数据类型, 一个被说明为该“联合”类型的变量中,允许装入该“联合”所定义的任何一种数据,这些数据共享同一段内存,已达到节省空间的目的(还有一个节省空间的类型:位域)。 这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且,也具有成员函数。

2、联合与结构的区别? 
   “联合”与“结构”有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在“联合”中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。

3、如何定义? 
   例如:

    union test 
    { 
      test() { } 
      int office; 
      char teacher[5]; 
    }; 

定义了一个名为test的联合类型,它含有两个成员,一个为整型,成员名为office;另一个为字符数组,数组名为teacher。联合定义之后,即可进行联合变量说明,被说明为test类型的变量,可以存放整型量office或存放字符数组teacher。

4、如何说明? 
   联合变量的说明有三种形式:先定义再说明、定义同时说明和直接说明。 
   以test类型为例,说明如下:


    1) union test 
       { 
         int office; 
         char teacher[5]; 
       }; 
       union test a,b;    /*说明a,b为test类型*/ 
    2) union test 
       { 
         int office; 
         char teacher[5]; 
       } a,b; 
    3) union 
       { 
         int office; 
         char teacher[5]; 
       } a,b; 

经说明后的a,b变量均为test类型。 
    a,b变量的长度应等于test的成员中最长的长度,即等于teacher数组的长度,共5个字节。a,b变量如赋予整型值时,只使用了4个字节,而赋予字符数组时,可用5个字节。

5、如何使用? 
   对联合变量的赋值,使用都只能是对变量的成员进行。 
   联合变量的成员表示为:联合变量名.成员名 
   例如,a被说明为test类型的变量之后,可使用a.class、a.office 
   不允许只用联合变量名作赋值或其它操作,也不允许对联合变量作初始化赋值,赋值只能在程序中进行。 
   还要再强调说明的是,一个联合变量,每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变员的某一个成员值。

6、匿名联合 
   匿名联合仅仅通知编译器它的成员变量共同享一个地址,而变量本身是直接引用的,不使用通常的点号运算符语法.例如:


     #include <iostream> 
     void main() 
     { 
         union{ 
                int test; 
                char c; 
               };          
        test=5; 
        c=''a''; 
        std::cout<<i<<" "<<c; 
     } 

正如所见到的,联合成分象声明的普通局部变量那样被引用,事实上对于程序而言,这也正是使用这些变量的方式.另外,尽管被定义在一个联合声明中,他们与同一个程序快那的任何其他局部变量具有相同的作用域级别.这意味这匿名联合内的成员的名称不能与同一个作用域内的其他一直标志符冲突. 
    对匿名联合还存在如下限制: 
    因为匿名联合不使用点运算符,所以包含在匿名联合内的元素必须是数据,不允许有成员函数,也不能包含私有或受保护的成员。还有,全局匿名联合必须是静态(static)的,否则就必须放在匿名名字空间中。

7、几点需要讨论的地方: 
   1、联合里面那些东西不能存放? 
      我们知道,联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。 
   2、类可以放入联合吗? 
      我们先看一个例子:


      class Test 
      { 
      public: 
          Test():data(0) { } 
      private: 
          int data; 
      };       typedef union _test 
     { 
              Test test; 
     }UI;

编译通不过,为什么呢? 
     因为联合里不允许存放带有构造函数、析够函数、复制拷贝操作符等的类,因为他们共享内存,编译器无法保证这些对象不被破坏,也无法保证离开时调用析够函数。

8、又是匿名惹的祸?? 
       我们先看下一段代码:


 1 class test 
 2 { 
 3         public: 
 4              test(const char* p); 
 5              test(int in); 
 6              const operator char*() const {return data.ch;} 
 7              operator long() const {return data.l;} 
 8         private: 
 9         enum type {Int, String }; 
10          union 
11          { 
12               const char* ch; 
13               int i; 
14          } datatype; 
15         type stype; 
16         test(test&); 
17         test& operator=(const test&); 
18 }; 
19    test::test(const char *p):stype(String),datatype.ch(p)     { } 
20    test::test(int in):stype(Int),datatype.l(i)     { } 
21 

看出什么问题了吗?呵呵,编译通不过。为什么呢?难道datatype.ch(p)和datatype.l(i)有问题吗? 
     哈哈,问题在哪呢?让我们来看看构造test对象时发生了什么,当创建test对象时,自然要调用其相应的构造函数,在构造函数中当然要调用其成员的构造函数,所以其要去调用datatype成员的构造函数,但是他没有构造函数可调用,所以出错。 
     注意了,这里可并不是匿名联合!因为它后面紧跟了个data!

9、如何有效的防止访问出错? 
       使用联合可以节省内存空间,但是也有一定的风险:通过一个不适当的数据成员获取当前对象的值!例如上面的ch、i交错访问。 
       为了防止这样的错误,我们必须定义一个额外的对象,来跟踪当前被存储在联合中的值得类型,我们称这个额外的对象为:union的判别式。 
       一个比较好的经验是,在处理作为类成员的union对象时,为所有union数据类型提供一组访问函数。

C++联合的更多相关文章

  1. Dynamics CRM 之ADFS 使用 WID 的独立联合服务器

    ADFS 的使用 WID 的独立联合服务器适用于自己的测试环境,常用的就是在虚机中使用. 拓扑图如下: wID:联合身份验证服务配置为使用 Windows 内部数据库

  2. Dynamics CRM 之ADFS 使用 WID 的联合服务器场

    使用 WID 的联合服务器场 默认拓扑 Active Directory 联合身份验证服务 (AD FS) 是联合服务器场,使用 Windows 内部数据库 (WID). 在这种拓扑, AD FS 使 ...

  3. Hibernate(5)—— 联合主键 、一对一关联关系映射(xml和注解) 和 领域驱动设计

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to One 映射关系 一对一单向外键(XML/Annotation) 一对一双向外键关联(XML/A ...

  4. Federated Identity Pattern 联合身份模式

    Delegate authentication to an external identity provider. This pattern can simplify development, min ...

  5. [占位-未完成]scikit-learn一般实例之十一:异构数据源的特征联合

    [占位-未完成]scikit-learn一般实例之十一:异构数据源的特征联合 Datasets can often contain components of that require differe ...

  6. SQL联合查询:子表任一记录与主表联合查询

    今天有网友群里提了这样一个关于SQL联合查询的需求: 一.有热心网友的方案: 二.我的方案: select * from ( select a.*,(select top 1 Id from B as ...

  7. Dynamics CRM 之ADFS 使用 SQL Server 的联合服务器场

    此拓扑用于 Active Directory 联合身份验证服务 (AD FS) 不同于使用 Windows 内部数据库 (WID) 部署拓扑,因为不会将数据复制到每台联合服务器场中的联合身份验证服务器 ...

  8. Dynamics CRM 之ADFS 使用 WID 和代理的联合服务器场

    为此部署拓扑 Active Directory 联合身份验证服务 (AD FS) 等同于联合服务器场与 Windows 内部数据库 (WID) 拓扑中,但它将代理服务器计算机添加到外围网络,以支持外部 ...

  9. Mysql联合,连接查询

    一. 联合查询    UNION, INTERSECT, EXCEPT UNION运算符可以将两个或两个以上Select语句的查询结果集合合并成一个结果集合显示,即执行联合查询.UNION的语法格式为 ...

  10. 利用联合双边滤波或引导滤波进行升采样(Upsampling)技术提高一些耗时算法的速度。

    这十年来,在图像处理领域提出了很多新的图像分析和处理方法,包括是自动的以及一些需要有人工参与的,典型的比如stereo depth computations.image colorization.to ...

随机推荐

  1. 用 FragmentManager 替换时使用 GoogleMaps 崩溃 app

    我要用下面的代码来加载的片段的项已被选定在 NavigationDrawer,然而 MapFragment 包含它里面的谷歌地图片段和它崩溃后试图打开它第二次. 这里是我使用的代码: @Overrid ...

  2. 使用IzPack打包JAVA Web应用程序

    使用IzPack打包JAVA Web应用程序步骤如下: 这里使用IzPack-4.3.5 + launch4j-3.1.0-beta1-win32.zip(绿色版)对Web应用程序打包,打包后即可对我 ...

  3. git 教程(7)--撤销修改

    自然,你是不会犯错的.不过现在是凌晨两点,你正在赶一份工作报告,你在readme.txt中添加了一行:

  4. __get().__set.__isset,__unset魔术方法

    一般来说,总是把类的属性定义为 private .这更符合现实的逻辑. 但是对属性的读取和赋值操作非常频繁的,因此在PHP中,预定义了两魔术方法 "__get()"用来获取私有成员属性值的,只有一个参 ...

  5. HTTP协议概念篇

    1.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器. ...

  6. 调用pyxmpp库PyQt编程打包成exe文件出错

    pyxmpp库内resolver.py内getaddrinfo获取Openfire服务器地址出错

  7. 【工具】【版本控制】TortoiseSVN过滤文件与文件夹

    这些网上搜一大把,就直接截图过来了.

  8. mkdir:批量创建文件夹

    问题:mkdir dir[0-9]创建文件夹时,并没有如预期创建dir0~dir9这几个文件夹,而是创建了dir[0-9]这一个文件夹. 网上看了些相关资料,发现以前对[0-9]的理解不够透彻: &q ...

  9. 【leetcode】Search in Rotated Sorted Array

    Search in Rotated Sorted Array Suppose a sorted array is rotated at some pivot unknown to you before ...

  10. Unity3d 防止内存修改工具的小方法

    一个非常简单的方法,直接上代码. private int curATK; private int curAtkKey; public int CurATK { get { return curATK ...