struct,union,Class,bitfield各自的作用和区别
这四个概念是 C/C++ 中构建数据结构的核心基石。简单来说,它们都是用来组织数据的,但侧重点完全不同:
- struct :用来打包不同类型的数据(如一个"学生"包含姓名、年龄)。
- union :用来节省内存,同一时间只能存一种数据(如"身份证"和"护照"共用一个位置)。
- class :用来封装数据和行为,是面向对象的核心(如一个"银行账户"包含余额和存取款方法)。
- bitfield :用来极致压缩空间,精确到"位"(如只占 1 位的开关状态)。
1. 结构体
核心作用:数据的"打包容器"
struct 是最常用的聚合类型,用于将多个不同类型的数据组合在一起,描述一个事物的属性。
- 内存机制 :每个成员都有自己独立的内存空间 。结构体的总大小通常大于等于所有成员大小之和(因为存在内存对齐)。
- 访问方式:所有成员可以同时存在并被访问。
- C vs C++ :
- C语言 :只能包含数据成员,默认为
public。 - C++ :可以包含函数、构造函数等。默认访问权限是
public(这是与class的主要语法区别之一)。
- C语言 :只能包含数据成员,默认为
代码示例:
cpp
struct Student {
char name[20];
int age;
float score;
};
// sizeof(Student) 通常 >= 20+4+4 (受对齐影响)
// 每个成员都有独立的内存
2. 联合体
核心作用:内存的"节省神器"
union 看起来和结构体很像,但它的逻辑是"互斥"。它用于那些在同一时间只需要存储一种类型数据的场景。
- 内存机制 :所有成员共用同一块内存 。联合体的总大小等于其最大成员的大小(并满足对齐要求)。
- 访问方式:同一时间只能有一个成员是有效的。给一个成员赋值,会覆盖其他成员的数据。
- 典型场景 :
- 节省内存:在嵌入式系统中,RAM 极其宝贵。
- 数据类型转换 :例如将
int拆分为 4 个char来分析字节(大小端检测)。
代码示例:
cpp
union Data {
int i;
float f;
char str[4];
};
// sizeof(Data) = 4 (假设 int 为 4 字节,且是最大成员)
// 内存是共用的,修改 i 会影响 f 和 str 的值
3. 类
核心作用:面向对象的"蓝图"
class 是 C++ 面向对象编程(OOP)的核心。它不仅包含数据,还包含操作数据的方法(行为),强调封装、继承和多态。
- 内存机制 :与
struct类似,成员变量占用独立内存。 - 核心特性 :
- 封装 :通过
private、protected隐藏内部实现细节,只暴露public接口。 - 行为:可以包含构造函数、析构函数、虚函数等。
- 封装 :通过
- C++ 中与 struct 的区别 :
- 默认访问权限 :
class的成员默认是private的,而struct默认是public的。 - 默认继承方式 :
class默认是私有继承,struct默认是公有继承。 - 语义 :
class通常用于既有数据又有行为的复杂对象,struct通常用于纯数据载体(POD)。
- 默认访问权限 :
代码示例:
cpp
class BankAccount {
private: // 默认就是 private
double balance;
public:
void deposit(double amount) { balance += amount; } // 行为
double getBalance() { return balance; }
};
4. 位域
核心作用:空间的"极致压缩"
位域(Bit Field)是一种特殊的结构体或联合体成员,允许你指定成员占用的具体位数(如 1 位、3 位)。
- 内存机制 :多个位域成员可以挤在同一个字节里。例如,两个
int:1的成员只占 2 个位,而不是 8 个字节。 - 典型场景 :
- 嵌入式/硬件驱动:直接映射硬件寄存器(如某个寄存器第 0 位是开关,第 1-3 位是模式)。
- 网络协议:解析 IP 头等紧凑的数据包格式。
- 缺点 :可移植性差。位域的内存布局(大端/小端、对齐方式)依赖于编译器,不同编译器下结果可能不同。
代码示例:
cpp
struct HardwareReg {
unsigned int enable : 1; // 只占 1 位
unsigned int mode : 3; // 只占 3 位
unsigned int error : 1; // 只占 1 位
// 总共只占 5 位,通常会被塞进一个字节或 int 中
};
总结对比表
| 特性 | struct | union | class | bitfield |
|---|---|---|---|---|
| 核心用途 | 数据打包,描述事物属性 | 节省内存,多类型复用 | 封装数据与行为 (OOP) | 极致压缩,硬件映射 |
| 内存占用 | 各成员独立,总和+对齐 | 成员共用,取最大值 | 同 struct | 按位分配,多个成员挤在一起 |
| 数据共存 | ✅ 所有成员同时有效 | ❌ 同一时间仅一个有效 | ✅ 所有成员同时有效 | ✅ 同时有效 |
| 默认访问权限 (C++) | public | public | private | (取决于所在结构) |
| 典型场景 | 数据传输对象、配置项 | 变体数据类型、协议解析 | 业务对象、复杂逻辑 | 硬件寄存器、协议头 |
struct union class 都可以设置构造函数?和几个特殊的构造函数吗? 他们都可以设置private protected,public???
- 构造函数 :
struct和class完全一样,都可以定义构造函数;union也可以,但限制较多。 - 访问控制 :它们都可以 设置
private、protected、public,区别只在于默认的权限不同。
1. 构造函数:它们都能用吗?
在 C++ 中,struct、union 和 class 本质上都是"类类型",它们都可以拥有构造函数,但能力有所不同。
✅ struct 和 class:完全体
这两者在构造函数方面没有任何区别。
- 都可以定义默认构造函数、带参构造函数。
- 都可以定义拷贝构造函数、移动构造函数。
- 都可以重载
=运算符。 - 都可以定义析构函数。
⚠️ union:受限体
union 也可以有构造函数,但因为它特殊的内存共享机制(所有成员共用一块内存),有一些特殊规则:
- 不能有虚函数 :因为
union通常用于底层内存操作,不支持多态。 - 不能有引用类型的成员:因为不同成员大小可能不同,引用无法正确绑定。
- 不能有静态成员(C++11 之前)。
- 如果成员有非平凡构造函数 :如果你的
union里有一个std::string或者自定义类,你需要手动编写union的构造函数来初始化它(或者使用定位 new),编译器不会自动生成。
代码示例:
cpp
struct MyStruct {
MyStruct() { /* 结构体构造函数 */ }
};
class MyClass {
public:
MyClass() { /* 类构造函数 */ }
};
union MyUnion {
int i;
double d;
// Union 的构造函数
MyUnion() : i(0) {}
};
2. 访问控制:private / protected / public
答案是肯定的:它们都可以使用这三个关键字。
但是,默认的访问权限不同,这是它们在语法上最大的区别。
📊 权限对比表
| 特性 | struct | class | union |
|---|---|---|---|
| 默认成员权限 | public (公开) | private (私有) | public (公开) |
| 默认继承权限 | public (公开继承) | private (私有继承) | (通常不用于继承) |
| 能否用 private | 能 | 能 | 能 |
| 能否用 protected | 能 | 能 | 能 |
-
struct 默认是"坦诚"的 :
如果你不写
public:或private:,编译器默认所有成员都是public的。这符合 C 语言遗留下来的习惯------struct主要用来存数据,数据通常是公开访问的。 -
class 默认是"封闭"的 :
如果你不写访问修饰符,编译器默认所有成员都是
private的。这符合面向对象编程(OOP)的封装原则------隐藏内部实现细节,只暴露接口。 -
union 默认是"坦诚"的 :
和
struct一样,默认是public。
实战:如何手动设置权限
即使 struct 默认是公开的,你依然可以强制把它变成私有的;反之亦然。
在 struct 中使用 private:
cpp
struct SecretData {
private: // 强制设为私有
int password;
public:
void setPassword(int p) { password = p; }
};
在 class 中使用 public:
cpp
class PublicConfig {
public: // 强制设为公开
int version;
private:
void internalLogic() {}
};
3. 几个特殊的构造函数
除了普通的构造函数,C++ 中还有几个特殊的构造函数,struct 和 class 都可以拥有它们:
- 默认构造函数:无参或所有参数都有默认值。
- 拷贝构造函数 :
Class(const Class& other),用于对象复制。 - 移动构造函数 :
Class(Class&& other),C++11 引入,用于资源转移(高效)。 - 拷贝赋值运算符 :
operator=(const Class&),虽然不是构造函数,但常与构造函数一起讨论(Rule of Three/Five)。 - 析构函数 :
~Class(),对象销毁时调用。
总结:
- 如果你想要一个纯数据载体 ,用
struct(默认 public,写起来省事)。 - 如果你想要一个功能完备的对象 ,需要封装和继承,用
class(默认 private,更安全)。 - 如果你需要省内存 或者做底层数据解析 ,用
union。 - 无论用哪个,你都可以手动加上
private、protected或public来控制访问权限。