C++中的union

前言:

说实在的,平时很少用到union。今天偶尔用了一下,编译器就给了我一个下马威,一个看似没有问题的union定义被编译器抱怨有错误。看着那些莫名其妙的错误信息,一开始还真是摸不着头脑,看样子C++中的union和C中的union还真是不一样。先给大家看一个例子

class A
{
public:
  A() 
{}
  
int _k;
}
;

union B
{
  A _a;
}
;

int _tmain(int argc, _TCHAR* argv[])
{
  B b;
  b._a._k 
= 100;
  _getch();
  
return 0;
}


你觉得这段程序中,union的定义有没有问题?你可以用你的编译器试一下,然后在接着看下面的部分,^_^

正文:

C++中的union,很大程度上是为了兼容C语言才提出来的,看了下面的文章,你就会感觉到,C++中的union显得有些不伦不类。如果需要用到union,我们最好使用传统的union,也就是C中的union。至于下面提到的C++中的union独有的特点,在实际工作中,最好不要用;当然,了解一下还是有好处的,至少和朋友吹牛的时候可以用到,^_^

在C++中,union有以下特点:
1. union可以定义自己的函数,包括 constructor 以及 destructor。
2. union支持 public , protected 以及 private 权限。
读者看到这可能会问,要是这样的话,union与class还有什么区别吗?区别当然还是有的
3. union不支持继承。也就是说,union既不能有父类,也不能作为别人的父类。
4. union中不能定义虚函数。
5. 不是所有类型的变量都能作为union的成员变量。POD(注1)类型可以作为union的成员变量。如果一个类,包括其父类,含有自定义的constructor,copy constructor,destructor,copy assignment operator, virtual function中的任意一个,那么这种类型的变量不能作为union的成员变量。
6. union中可以定义static以及引用类型的成员变量,不过C++标准不推荐这样做,包含这样代码的程序是ill-formed的

如果我们在定义union的时候没有定义名字,那么这个union被称为匿名union(anonymous union)。匿名union的特点如下:

1. 匿名union中不能定义static变量。
2. 匿名union中不能定义函数。
3. 匿名union中不支持 protected 以及 private 权限。
4. 在全局域以及namespace中定义的匿名union只能是static的。

ok,写道最后,留一个问题给大家:
union {
   int aa;
   char* p;
}obj;
这里定义的union是不是匿名的union? 

注1: 什么是POD?
POD 的全称是 Plain Old Data,在C++标准中,POD是这样定义的:
Arithmetic types (3.9.1), enumeration types, pointer types, and pointer to member types (3.9.2), and cv-qualified(注2) versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD-struct types,POD-union types (clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called POD types.
我们可以这样理解POD,与C兼容的数据类型可以被成为POD类型。

注2:什么是cv-qualified ?
这里的CV分别是const 以及volatile的缩写。用const,volatile以及const volatile之一作修饰的变量被成为cv-qualified ,否则该变量是cv-unqualified

<think>我们正在讨论C++中的联合体(union)。根据引用内容,联合体是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型,但同一时间只能有一个成员是活跃的。联合体的大小由其最大成员决定。 接下来,我将按照用户的要求,详细解释C++ union的基本概念、使用方法和示例。 基本概念: 联合体(union)是C++中一种特殊的数据结构,它允许多个成员共享同一块内存空间。这意味着在任何时刻,联合体只能存储其中一个成员的值。给一个成员赋值会覆盖其他成员的值(因为它们共享内存)。 使用方法: 1. 定义联合体:使用关键字union,后跟联合体名称,然后在大括号内定义成员变量。 2. 声明联合体变量:和结构体类似,可以直接在定义时声明,也可以之后声明。 3. 访问成员:使用成员访问运算符(.)来访问联合体的成员。 注意事项: - 联合体的大小至少为其最大成员的大小(可能会因为内存对齐而更大)。 - 同一时间只能使用一个成员,否则会导致未定义行为。 - 联合体可以包含构造函数、析构函数和成员函数(在C++11之后),但也有一些限制(比如不能包含虚函数和引用类型的成员)。 示例: 我们将通过一个简单的例子来说明联合体的使用。这个例子定义了一个联合体Data,它可以存储整数、浮点数或字符串。 注意:由于联合体在C++11之前不能有非平凡类型(如std::string)的成员,所以在C++11之后,我们可以使用带有构造函数的成员,但需要手动管理构造和析构。然而,在示例中,我们使用字符数组来存储字符串,避免复杂类型的麻烦。 下面是一个示例代码:</think>### C++ 联合体(union)详解 #### 基本概念 联合体(union)是一种特殊的数据结构,**允许多个成员共享同一块内存空间**,但**同一时刻只能有一个成员处于活跃状态**。其核心特性包括: 1. **内存共享**:所有成员占用相同的内存起始地址 2. **大小决定**:联合体大小由其最大成员决定($sizeof(union) = \max(sizeof(members))$) 3. **类型互斥**:修改任一成员会覆盖其他成员的值 4. **内存对齐**:遵循系统的内存对齐规则 数学表示为:若联合体 $U$ 有成员 $m_1, m_2, \dots, m_n$,则: $$ \forall i,j \in [1,n], \quad \&m_i = \&m_j $$ $$ \text{size}(U) = \max_{1 \leq i \leq n}(\text{size}(m_i)) $$ #### 使用方法 1. **定义语法**: ```cpp union UnionName { member_type1 member1; member_type2 member2; // ... }; ``` 2. **访问规则**: ```cpp UnionName var; var.member1 = value; // 激活member1 // 此时访问var.member2将导致未定义行为[^2] ``` 3. **使用场景**: - 节省内存:处理互斥数据类型时 - 数据解释:同一内存的多种解释方式(如浮点数与字节数组转换) - 硬件映射:直接访问寄存器/设备内存的不同部分 #### 示例代码 ```cpp #include <iostream> #include <cstring> using namespace std; // 示例1:基础类型转换 union DataConverter { int intVal; float floatVal; char bytes[4]; }; // 示例2:复合数据结构(C++11扩展) struct Vector4 { union { float M[4]; // 数组表示 struct { // 结构体表示(匿名结构) float x, y, z, w; }; }; }; int main() { // 示例1使用 DataConverter dc; dc.floatVal = 3.14f; cout << "Float: " << dc.floatVal << endl; cout << "Integer: " << dc.intVal << endl; // IEEE754浮点数的整数表示 cout << "Bytes: "; for(int i=0; i<4; ++i) cout << hex << (int)dc.bytes[i] << " "; // 内存字节表示 // 示例2使用 Vector4 vec; vec.x = 1.0f; vec.y = 2.0f; vec.z = 3.0f; vec.w = 4.0f; cout << "\nArray: "; for(int i=0; i<4; ++i) cout << vec.M[i] << " "; // 输出:1 2 3 4 vec.M[2] = 99.0f; // 修改数组元素 cout << "\nZ-component: " << vec.z; // 输出99 } ``` #### 关键注意事项 1. **类型安全**:需自行确保访问正确的活跃成员 2. **生命周期管理**: - 包含非平凡类型(如string)需手动管理构造/析构(C++11起支持) - 默认平凡构造函数/析构函数 3. **内存布局**:可使用`#pragma pack`控制对齐方式 4. **匿名联合**:C++11支持匿名联合,可直接访问成员(如示例2) > **输出示例**: > ``` > Float: 3.14 > Integer: 1078523331 > Bytes: c3 f5 48 40 > Array: 1 2 3 4 > Z-component: 99 > ``` [^1]: 联合体允许在相同内存位置存储不同数据类型,但同一时间只能使用一个成员 [^2]: 同时访问多个成员会导致未定义行为 [^3]: 匿名联合支持同一内存的多种访问方式
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值