(大卫的阅读笔记)C++中使用union的几点思考

大卫注 :
这段时间整理旧资料 ,看到一些文章 ,虽然讲的都是些小问题 ,不大可能用到 ,但也算是一个知识点 ,特整理出来与大家共享 .与此相关的那篇文章的作者的有些理解是错误的 ,我写此文 ,也是纠正为了作者的一些错误认识 .当然 ,如果我的理解有任何错误 ,也恳请大家批评指正 .

C ++虽说被B .S .称作一门新语言 ,但它毕竟与C有着千丝万缕的联系 ,虽然B .S .一再坚持 ,但我还是愿意把C ++看作是C  ++.
我们应该按照C中的convention去使用 union ,这是我这篇文章要给出的观点 .虽然C ++使得我们可以扩展一些新的东西进去 ,但是 ,我建议你不要那样去做 ,看完这篇文章之后 ,我想你大概也是这么想的 .

C由于没有类的概念 ,所有类型其实都可以看作是基本类型的组合 ,因此在 union中包含 struct也就是一件很自然的事情了 ,到了C ++之后 ,既然普遍认为C ++中的 structclass基本等价 ,那么 union中是否可以有类成员呢 ?先来看看如下的代码 :

struct
 TestUnion
{

    TestUnion () {}
};


typedef union

{

    TestUnion obj ;
}
 UT ;

int
 main  ( void )
{

    return
 0 ;
}


编译该程序 ,我们将被告知 :
error C2620 :  union  '__unnamed'  : member  'obj' has user -defined constructor  or non -trivial  default constructor
而如果去掉那个什么也没干的构造函数 ,则一切OK .

为什么编译器不允许我们的 union成员有构造函数呢 ?我无法找到关于这个问题的比较权威的解释 ,对这个问题 ,我的解释是 :
如果C ++标准允许我们的 union有构造函数 ,那么 ,在进行空间分配的时候要不要执行这个构造函数呢 ?如果答案是yes ,那么如果TestUnion的构造函数中包含了一些内存分配操作 ,或者其它对整个application状态的修改 ,那么 ,如果我今后要用到obj的话 ,事情可能还比较合理 ,但是如果我根本就不使用obj这个成员呢 ?由于obj的引入造成的对系统状态的修改显然是不合理的 ;反之 ,如果答案是no ,那么一旦我们今后选中了obj来进行操作 ,则所有信息都没有初始化 (如果是普通的 struct ,没什么问题 ,但是 ,如果有虚函数呢 ?).更进一步 ,假设现在我们的 union不是只有一个TestUnion obj ,还有一个TestUnion2 obj2 ,二者均有构造函数 ,并且都在构造函数中执行了一些内存分配的工作 (甚至干了很多其它事情 ),那么 ,如果先构造obj ,后构造obj2 ,则执行的结果几乎可以肯定会造成内存的泄漏 .
鉴于以上诸多麻烦 (可能还有更多麻烦 ),在构造 union,编译器只负责分配空间 ,而不负责去执行附加的初始化工作 ,为了简化工作 ,只要我们提供了构造函数 ,就会收到上面的error .
同理 ,除了不能加构造函数 ,析构函数 /拷贝构造函数 /赋值运算符也是不可以加 .

此外 ,如果我们的类中包含了任何 virtual函数 ,编译时 ,我们将收到如下的错误信息 :
error C2621 :  union  '__unnamed'  : member  'obj' has copy constructor

所以 ,打消在 union中包含有构造函数 /析构函数 /拷贝构造函数 /赋值运算符 /虚函数的类成员变量的念头 ,老老实实用你的C风格 struct!
不过 ,定义普通的成员函数是OK的 ,因为这不会使得 class与C风格的 struct有任何本质区别 ,你完全可以将这样的 class理解为一个C风格的 struct  + n个全局函数 .

现在 ,再看看在类中包含内部 union时会有什么不同 .看看下面的程序 ,并请注意阅读程序提示 :

class
 TestUnion
{

    union
 DataUnion
    {

        DataUnion ( const  char *);
        DataUnion ( long );
        const
 char * ch_ ;
        long
       l_ ;
    }
 data_ ;

public
:
    TestUnion ( const  char * ch );
    TestUnion ( long l );
};


TestUnion ::TestUnion ( const  char * ch ) : data_ (ch )  // if you want to use initialzing list to initiate a nested-union member, the union must not be anonymous and must have a constructor.
{
}


TestUnion ::TestUnion ( long l ) : data_ (l )
{
}


TestUnion ::DataUnion ::DataUnion ( const  char * ch ) : ch_ (ch )
{
}


TestUnion ::DataUnion ::DataUnion ( long l ) : l_ (l )
{
}


int
 main  ( void )
{

    return
 0 ;
}


正如上面程序所示 ,C ++中的 union也可以包含构造函数 ,但是 ,这虽然被语言所支持 ,但实在是一种不佳的编程习惯 ,因此 ,我不打算对上面的程序进行过多的说明 .我更推荐如下的编程风格 :

class
 TestUnion
{

    union
 DataUnion
    {

        const
 char * ch_ ;
        long
       l_ ;
    }
 data_ ;
    
public
:
    TestUnion ( const  char * ch );
    TestUnion ( long l );
};


TestUnion ::TestUnion ( const  char * ch )
{

    data_ .ch_  = ch ;
}


TestUnion ::TestUnion ( long l )
{

    data_ .l_  = l ;
}


int
 main  ( void )
{

    return
 0 ;
}


它完全是C风格的 .

所以 ,接受这个结论吧 :
请按照C中的convention去使用 union ,尽量不要尝试使用任何C ++附加特性 .
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值