C++派生数据类型与类型转换全解析(结构体、类、枚举、联合体对比+完整示例)
目录
一、C++ 数据类型体系概览
二、常见派生数据类型及示例
三、结构体 vs 类 vs 联合体 vs 枚举
✅ 示例 1:结构体 struct
✅ 示例 2:类 class
✅ 示例 3:联合体 union
✅ 示例 4:枚举 enum
四、类型别名:typedef 与 using
五、标准库常用类型总结
六、四种类型转换总结
示例 1:static_cast
示例 2:dynamic_cast
示例 3:const_cast
示例 4:reinterpret_cast
七、总结对比表
八、结语
一、C++ 数据类型体系概览
在 C++ 中,数据类型可以分为三大类:
| 类型类别 | 说明 | 举例 |
|---|---|---|
| 基本数据类型 | 由语言内置的原生类型 | int, float, double, char, bool |
| 派生数据类型 | 基于基本类型组合或封装而成 | 数组、指针、引用、函数、结构体、类、联合体、枚举 |
| 抽象/用户定义类型 | 用户通过 class、struct、enum、union 等方式自定义 | MyClass, Point, Color |
二、常见派生数据类型及示例
| 数据类型 | 描述 | 示例 |
|---|---|---|
| 数组 | 一组相同类型元素的集合 | int arr[5] = {1, 2, 3, 4, 5}; |
| 指针 | 存储变量内存地址 | int* ptr = &x; |
| 引用 | 变量的别名(必须初始化) | int& ref = x; |
| 函数 | 封装一段逻辑运算 | int func(int a, int b); |
| 结构体 struct | 聚合不同类型成员(默认公有) | struct Point {int x; int y;}; |
| 类 class | 支持封装、继承、多态(默认私有) | class MyClass {private: int data; }; |
| 联合体 union | 多成员共享一段内存 | union Data {int i; float f;}; |
| 枚举 enum | 一组具名整型常量集合 | enum Color {RED, GREEN, BLUE}; |
三、结构体 vs 类 vs 联合体 vs 枚举
| 特性 | 结构体(struct) | 类(class) | 联合体(union) | 枚举(enum) |
|---|---|---|---|---|
| 定义方式 | struct 名 {成员;}; | class 名 {成员;}; | union 名 {成员;}; | enum 名 {常量列表}; |
| 默认访问权限 | public | private | public | public |
| 内存分配 | 每个成员独占内存 | 每个成员独占内存 | 所有成员共享同一块内存 | 每个枚举常量为整型值 |
| 用途 | 聚合不同类型数据 | 面向对象封装与继承 | 存储互斥数据 | 定义常量集合 |
| 支持函数 | ✅ 可以包含函数 | ✅ 成员函数、构造、析构 | ❌ 不支持成员函数 | ❌ 不支持成员函数 |
| 封装性 | 弱 | 强 | 无 | 无 |
| 示例场景 | 点坐标、传感器数据 | 机器人类、控制器类 | 多格式数据表示 | 状态机状态定义 |
✅ 示例 1:结构体 struct
#include <iostream>
using namespace std;struct Point {int x;int y;void print() {cout << "Point(" << x << ", " << y << ")" << endl;}
};int main() {Point p1 = {3, 4};p1.print();return 0;
}
输出:
Point(3, 4)
✅ 示例 2:类 class
#include <iostream>
using namespace std;class Rectangle {
private:int width, height;
public:Rectangle(int w, int h) : width(w), height(h) {}int area() { return width * height; }
};int main() {Rectangle rect(5, 6);cout << "Area = " << rect.area() << endl;return 0;
}
输出:
Area = 30
🔍 区别:
struct默认成员是 public,class默认是 private。除此之外几乎完全等价。
✅ 示例 3:联合体 union
#include <iostream>
using namespace std;union Data {int i;float f;char c;
};int main() {Data data;data.i = 10;cout << "i = " << data.i << endl;data.f = 3.14;cout << "f = " << data.f << endl;cout << "i (after f assigned) = " << data.i << endl; // 同块内存被覆盖return 0;
}
输出(内存被覆盖):
i = 10
f = 3.14
i (after f assigned) = 1078523331
⚠️
union共享同一段内存,只能使用其中一个成员,典型应用是节省空间(如协议帧解析、字节重解释)。
✅ 示例 4:枚举 enum
#include <iostream>
using namespace std;enum Color { RED, GREEN = 5, BLUE };int main() {Color c = BLUE;cout << "RED = " << RED << ", GREEN = " << GREEN << ", BLUE = " << BLUE << endl;cout << "c = " << c << endl;return 0;
}
输出:
RED = 0, GREEN = 5, BLUE = 6
c = 6
🎨 枚举让代码更可读,不必再用“魔法数字”。
四、类型别名:typedef 与 using
C++ 提供两种定义别名的方式:
| 关键字 | 语法 | 示例 | 备注 |
|---|---|---|---|
typedef | typedef 原类型 新名; | typedef int MyInt; | C 时代传统写法 |
using | using 新名 = 原类型; | using MyInt = int; | C++11 推荐写法 |
示例:
typedef unsigned long ulong_t;
using ushort_t = unsigned short;ulong_t a = 100;
ushort_t b = 200;
五、标准库常用类型总结
| 类型 | 功能 | 示例 |
|---|---|---|
std::string | 字符串类型 | std::string s = "Hello"; |
std::vector | 动态数组 | std::vector<int> v = {1, 2, 3}; |
std::array | 固定大小数组(C++11) | std::array<int,3> a = {1,2,3}; |
std::pair | 存储两个值的键值对 | std::pair<int, string> p(1, "A"); |
std::map | 键值映射容器 | std::map<int, string> m; |
std::set | 唯一值集合 | std::set<int> s = {1,2,3}; |
六、四种类型转换总结
| cast | 作用 | 何时用 | 失败时表现 | 风险级别 |
|---|---|---|---|---|
|
| 编译期能判定的常规转换(数值、指针上下行的受限情况、显式构造、void*↔T* 等) | 不需要运行期检查、转换语义明确时 | 编译不过 | 低 |
dynamic_cast | 运行期带 RTTI 的安全向下转型/交叉转型(必须多态:基类里有虚函数) | 基类指针/引用要转回真实派生类型时 | 指针版返回 nullptr;引用版抛 std::bad_cast | 低~中 |
|
| 增/删顶层 const/volatile 限定 | 接口不匹配(如第三方 API 少了 const)且底层对象本身可改 | —— | 中(误用=UB) |
reinterpret_cast | 重新解释位模式(原类型与目标类型无语义关系) | 极少用;底层/硬件/序列化场景,且你能掌控 ABI/对齐/别名规则 | —— | 高(极易 UB) |
static(静态可判定)、dynamic(运行期检查)、const(只改限定符)、reinterpret(重新解释位)。
示例 1:static_cast
int i = 42;
float f = static_cast<float>(i);
解释:把 int 转 float,这是标准的算术类型提升,static_cast 完全胜任且最清晰。
特点:
-
编译期就能确定可行,失败会直接报错。
-
对于窄化(如
double → int)仍然允许,但可能丢精度——“可编译≠无信息损失”。 -
比 C 风格
(float)i更“窄”,不会悄悄做const去除或 reinterpret 之类的危险事。
实战建议:
-
所有“正常的数值类型转换”都首选
static_cast。 -
有窄化可能时,最好自己加注释或显式检查范围。
示例 2:dynamic_cast
class Base { public: virtual ~Base() {} };
class Derived : public Base { public: void show(){ cout<<"Derived\n"; } };Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b);
if (d) d->show(); // 输出 Derived
解释:
-
基类里定义了虚析构函数 ⇒
Base成为多态类型。 -
b实际指向Derived,所以dynamic_cast<Derived*>(b)成功,返回非空指针。 -
如果真实对象不是
Derived,指针版dynamic_cast会返回nullptr;引用版会抛std::bad_cast。
何时用:
-
你“手里只有基类指针/引用”,需要在运行期确认真实类型并向下转回派生类。
-
类层次复杂(菱形、多重继承)或需要交叉转型(同一最底层对象的另一个基类视图)。
对比 static_cast:
-
static_cast<Derived*>(Base*)不会做运行期检查,错了就是 UB。 -
能用
dynamic_cast的下行转型,除非你 100% 能证明类型关系,否则优先dynamic_cast。
示例 3:const_cast
const int ci = 10;
int& ri = const_cast<int&>(ci);
ri = 20;
std::cout << ri; // 输出 20(表面上),但这是未定义行为(UB)
关键点:
-
你把一个真正的常量对象
ci的const去掉后写入了它。 -
标准明确规定:如果原对象是
const,通过去除const后写入属于未定义行为(UB)。-
UB 的表现可能是看起来“成功了”、也可能崩溃、也可能被编译器优化掉,不可依赖。
-
正确用法(只在原对象本身是非常量时移除 const):
void takes_int_ref(int&); // 第三方旧接口,不带 const
void takes_int_cref(const int&); // 新接口,带 constvoid demo() {int x = 10; // 注意:x 是非 constconst int& cx = x; // 顶层 const 的“视图”// 正确:底层对象可写,只是我们手里拿的是 const 视图takes_int_ref(const_cast<int&>(cx));
}
实战建议:
-
const_cast只用于API 适配(对方函数签名不合理),且你能确认底层对象是可修改的。 -
永远不要对真正的常量(如
const int ci;、static const、放在只读段的对象)做写入。
示例 4:reinterpret_cast
const int ci = 10;
int& ri = const_cast<int&>(ci);
ri = 20;
std::cout << ri; // 输出 20(表面上),但这是未定义行为(UB)
问题很大:
-
严格别名规则(strict aliasing):通过不相关类型(
int↔float)的引用别名同一内存属于 UB。 -
对齐/大小:若类型对齐不同或大小不同,也可能 UB。
-
可移植性:假设了目标机器
int与float尺寸/编码与你的常量匹配(未必成立)。
更安全的现代写法(C++20 起):std::bit_cast
#include <bit>
#include <cstdint>uint32_t u = 0x40490fdbu; // 明确位宽
float f = std::bit_cast<float>(u); // 位级无 UB 的拷贝
std::cout << f << '\n';
实战建议:
-
reinterpret_cast几乎只在你完全确定 ABI/内存布局的底层场景才用;一般业务/库代码避免。 -
只想“把指针当字节地址打印/存储”?用
std::uintptr_t做中转;只想按位搬运?用bit_cast/memcpy。
七、总结对比表
| 类型 | 是否支持函数 | 内存共享 | 是否面向对象 | 默认权限 | 典型用途 |
|---|---|---|---|---|---|
struct | ✅ | ❌ | ❌ | public | 聚合数据 |
class | ✅ | ❌ | ✅ | private | 封装/继承/多态 |
union | ❌ | ✅ | ❌ | public | 节省空间 |
enum | ❌ | ❌ | ❌ | public | 常量集合 |
八、结语
💬 一句话总结:
struct:数据打包;
class:对象封装;
union:内存共用;
enum:枚举常量;
typedef/using:起别名方便代码阅读;
static_cast/dynamic_cast/const_cast/reinterpret_cast:类型转换的四种武器。
