首页 > 应用开发 > IT综合 > C++自定义数据类型:结构体、联合体与枚举深度应用
# C++自定义数据类型:结构体、联合体与枚举深度应用
## 结构体:数据聚合的基础
结构体是C++中用于将不同类型数据组合成单一数据类型的关键特性。从C语言继承而来,C++中的结构体得到了显著增强,支持成员函数、访问控制等面向对象特性。
```cpp
// 基础结构体定义
struct Point {
// 成员变量
double x;
double y;
// 构造函数(C++11起可以在结构体中定义)
Point() : x(0.0), y(0.0) {
std::cout << "默认构造函数" << std::endl;
}
Point(double x_val, double y_val) : x(x_val), y(y_val) {
std::cout << "参数化构造函数" << std::endl;
}
// 成员函数
void display() const {
std::cout << "(" << x << ", " << y << ")" << std::endl;
}
double distanceFromOrigin() const {
return std::sqrt(x * x + y * y);
}
// 操作符重载
Point operator+(const Point& other) const {
return Point(x + other.x, y + other.y);
}
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
// 使用结构体
void basic_struct_demo() {
// 创建结构体实例
Point p1; // 调用默认构造函数
p1.x = 3.0;
p1.y = 4.0;
Point p2(1.5, 2.5); // 调用参数化构造函数
// 使用成员函数
p1.display();
std::cout << "距离原点: " << p1.distanceFromOrigin() << std::endl;
// 使用操作符重载
Point p3 = p1 + p2;
p3.display();
// 结构体数组
Point points[3] = {
{1.0, 2.0},
{3.0, 4.0},
{5.0, 6.0}
};
}
```
## 高级结构体特性
### 结构体内存对齐与优化
```cpp
#include <iostream>
#include <cstddef> // for offsetof
// 非优化结构体
struct UnoptimizedData {
char a; // 1字节
int b; // 4字节,可能需要3字节填充
double c; // 8字节
char d; // 1字节,可能需要7字节填充
};
// 优化结构体(按对齐要求排序)
struct OptimizedData {
double c; // 8字节(最大对齐要求)
int b; // 4字节
char a; // 1字节
char d; // 1字节
// 可能只需要2字节填充
};
void memory_alignment_demo() {
std::cout << "结构体内存布局分析:" << std::endl;
std::cout << "sizeof(UnoptimizedData): " << sizeof(UnoptimizedData) << " 字节" << std::endl;
std::cout << "sizeof(OptimizedData): " << sizeof(OptimizedData) << " 字节" << std::endl;
// 使用offsetof宏查看成员偏移
std::cout << "\n成员偏移量:" << std::endl;
std::cout << "UnoptimizedData::a: " << offsetof(UnoptimizedData, a) << std::endl;
std::cout << "UnoptimizedData::b: " << offsetof(UnoptimizedData, b) << std::endl;
std::cout << "UnoptimizedData::c: " << offsetof(UnoptimizedData, c) << std::endl;
std::cout << "UnoptimizedData::d: " << offsetof(UnoptimizedData, d) << std::endl;
std::cout << "\nOptimizedData::c: " << offsetof(OptimizedData, c) << std::endl;
std::cout << "OptimizedData::b: " << offsetof(OptimizedData, b) << std::endl;
std::cout << "OptimizedData::a: " << offsetof(OptimizedData, a) << std::endl;
std::cout << "OptimizedData::d: " << offsetof(OptimizedData, d) << std::endl;
}
// 位域:节省内存的特殊结构体
struct BitFieldDemo {
// 位域声明
unsigned int flag1 : 1; // 1位
unsigned int flag2 : 2; // 2位
unsigned int flag3 : 3; // 3位
unsigned int : 2; // 2位无名位域,用于填充
unsigned int value : 8; // 8位
unsigned int : 0; // 强制对齐到下一个分配单元边界
// 普通成员
int regular_member;
};
void bitfield_demo() {
BitFieldDemo bf;
std::cout << "\n位域示例:" << std::endl;
std::cout << "sizeof(BitFieldDemo): " << sizeof(BitFieldDemo) << " 字节" << std::endl;
// 设置位域值
bf.flag1 = 1; // 只能存储0或1
bf.flag2 = 2; // 可以存储0-3(2位)
bf.flag3 = 5; // 可以存储0-7(3位)
bf.value = 255; // 可以存储0-255(8位)
std::cout << "flag1: " << bf.flag1 << std::endl;
std::cout << "flag2: " << bf.flag2 << std::endl;
std::cout << "flag3: " << bf.flag3 << std::endl;
std::cout << "value: " << bf.value << std::endl;
}
```
### 匿名结构体与灵活应用
```cpp
// 嵌套结构体
struct Employee {
struct PersonalInfo {
std::string name;
int age;
std::string id_number;
void display() const {
std::cout << "姓名: " << name
<< ", 年龄: " << age
<< ", 身份证: " << id_number << std::endl;
}
};
struct WorkInfo {
std::string department;
std::string position;
double salary;
int employee_id;
void display() const {
std::cout << "部门: " << department
<< ", 职位: " << position
<< ", 工资: " << salary
<< ", 工号: " << employee_id << std::endl;
}
};
PersonalInfo personal;
WorkInfo work;
void display() const {
std::cout << "\n员工信息:" << std::endl;
personal.display();
work.display();
}
};
// 匿名结构体(C++11起支持)
struct AnonymousStructDemo {
struct {
int x;
int y;
} point; // 匿名结构体成员
struct {
int width;
int height;
}; // 完全匿名结构体,成员直接访问
void demo() {
point.x = 10;
point.y = 20;
width = 100; // 直接访问匿名结构体成员
height = 200;
std::cout << "点: (" << point.x << ", " << point.y << ")" << std::endl;
std::cout << "尺寸: " << width << "x" << height << std::endl;
}
};
// 灵活数组成员(C风格,C++中需谨慎使用)
struct FlexibleArray {
int length;
double data[]; // 灵活数组成员,必须是最后一个成员
};
void flexible_array_demo() {
// 动态分配包含灵活数组的结构体
int required_size = 10;
size_t total_size = sizeof(FlexibleArray) + required_size * sizeof(double);
FlexibleArray* fa = reinterpret_cast<FlexibleArray*>(new char[total_size]);
fa->length = required_size;
for (int i = 0; i < required_size; ++i) {
fa->data[i] = i * 1.5;
}
std::cout << "\n灵活数组内容:" << std::endl;
for (int i = 0; i < fa->length; ++i) {
std::cout << fa->data[i] << " ";
}
std::cout << std::endl;
delete[] reinterpret_cast<char*>(fa);
}
```
## 联合体:内存共享的高级特性
### 基础联合体应用
```cpp
// 基础联合体
union BasicUnion {
int int_value;
double double_value;
char char_value;
// C++11起,联合体可以有成员函数
void displayAsInt() const {
std::cout << "整数值: " << int_value << std::endl;
}
void displayAsDouble() const {
std::cout << "双精度值: " << double_value << std::endl;
}
void displayAsChar() const {
std::cout << "字符值: '" << char_value << "' (ASCII: "
<< static_cast<int>(char_value) << ")" << std::endl;
}
};
void basic_union_demo() {
BasicUnion u;
std::cout << "联合体大小: " << sizeof(u) << " 字节" << std::endl;
u.int_value = 65;
u.displayAsInt();
u.displayAsChar(); // 显示字符'A'(ASCII 65)
u.double_value = 3.14159;
u.displayAsDouble();
// 注意:此时int_value和char_value的值未定义
}
// 带标记的联合体(安全使用)
struct TaggedUnion {
enum class Type { INT, DOUBLE, STRING };
Type current_type;
union {
int int_value;
double double_value;
char string_value[32];
};
TaggedUnion() : current_type(Type::INT) {
int_value = 0;
}
~TaggedUnion() {
// 如果存储了字符串,需要特殊处理
if (current_type == Type::STRING) {
// 字符串不需要特殊清理(字符数组)
}
}
void setInt(int value) {
current_type = Type::INT;
int_value = value;
}
void setDouble(double value) {
current_type = Type::DOUBLE;
double_value = value;
}
void setString(const std::string& value) {
current_type = Type::STRING;
strncpy(string_value, value.c_str(), sizeof(string_value) - 1);
string_value[sizeof(string_value) - 1] = '\0';
}
void display() const {
switch (current_type) {
case Type::INT:
std::cout << "整数: " << int_value << std::endl;
break;
case Type::DOUBLE:
std::cout << "浮点数: " << double_value << std::endl;
break;
case Type::STRING:
std::cout << "字符串: " << string_value << std::endl;
break;
}
}
};
```
### 匿名联合体与类型安全联合体
```cpp
// 匿名联合体
struct VariantData {
enum DataType { INT, FLOAT, TEXT };
DataType type;
// 匿名联合体
union {
int int_data;
float float_data;
char text_data[64];
};
VariantData() : type(INT) {
int_data = 0;
}
VariantData(int value) : type(INT) {
int_data = value;
}
VariantData(float value) : type(FLOAT) {
float_data = value;
}
VariantData(const std::string& str) : type(TEXT) {
strncpy(text_data, str.c_str(), sizeof(text_data) - 1);
text_data[sizeof(text_data) - 1] = '\0';
}
// 类型安全的访问
int getInt() const {
if (type != INT) {
throw std::runtime_error("不是整数类型");
}
return int_data;
}
float getFloat() const {
if (type != FLOAT) {
throw std::runtime_error("不是浮点类型");
}
return float_data;
}
std::string getText() const {
if (type != TEXT) {
throw std::runtime_error("不是文本类型");
}
return std::string(text_data);
}
};
// C++17的std::variant(类型安全联合体的现代替代)
#if __cplusplus >= 201703L
#include <variant>
#include <string>
void variant_demo() {
std::variant<int, double, std::string> data;
data = 42;
std::cout << "存储整数: " << std::get<int>(data) << std::endl;
data = 3.14159;
std::cout << "存储浮点数: " << std::get<double>(data) << std::endl;
data = "Hello Variant";
std::cout << "存储字符串: " << std::get<std::string>(data) << std::endl;
// 安全访问
try {
std::cout << std::get<int>(data) << std::endl;
} catch (const std::bad_variant_access& e) {
std::cout << "访问错误: " << e.what() << std::endl;
}
// 使用visit处理不同类型
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>) {
std::cout << "处理整数: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, double>) {
std::cout << "处理浮点数: " << arg << std::endl;
} else if constexpr (std::is_same_v<T, std::string>) {
std::cout << "处理字符串: " << arg << std::endl;
}
}, data);
}
#endif
```
## 枚举:类型安全的常量集合
### 基础枚举类型
```cpp
// 传统枚举(C风格)
enum Color {
RED, // 0
GREEN, // 1
BLUE, // 2
YELLOW = 10,
PURPLE // 11
};
// 作用域枚举(C++11)
enum class TrafficLight {
RED, // TrafficLight::RED
YELLOW, // TrafficLight::YELLOW
GREEN // TrafficLight::GREEN
};
enum class FileMode : uint8_t { // 指定底层类型
READ = 0x01,
WRITE = 0x02,
EXECUTE = 0x04,
READ_WRITE = READ | WRITE,
ALL = READ | WRITE | EXECUTE
};
void enum_demo() {
// 传统枚举
Color c = RED;
std::cout << "颜色值: " << c << std::endl;
// 作用域枚举(更安全)
TrafficLight light = TrafficLight::RED;
// 枚举值比较
if (light == TrafficLight::RED) {
std::cout << "红灯停" << std::endl;
}
// 转换为整数
int light_value = static_cast<int>(light);
std::cout << "交通灯值: " << light_value << std::endl;
// 位标志枚举
FileMode mode = FileMode::READ_WRITE;
if (static_cast<uint8_t>(mode) & static_cast<uint8_t>(FileMode::WRITE)) {
std::cout << "可写模式" << std::endl;
}
}
// 枚举类模板(C++14以后)
template<typename Enum>
struct EnumTraits {};
template<>
struct EnumTraits<Color> {
static constexpr const char* name = "Color";
static constexpr std::array<const char*, 5> names = {
"RED", "GREEN", "BLUE", "YELLOW", "PURPLE"
};
static const char* toString(Color c) {
switch (c) {
case RED: return "红色";
case GREEN: return "绿色";
case BLUE: return "蓝色";
case YELLOW: return "黄色";
case PURPLE: return "紫色";
default: return "未知颜色";
}
}
};
```
### 枚举高级应用
```cpp
// 枚举与开关语句的完美配合
class DeviceController {
public:
enum class DeviceState {
OFF,
STARTING,
RUNNING,
STOPPING,
ERROR
};
enum class ErrorCode {
NONE = 0,
OVERHEAT = 1,
POWER_FAILURE = 2,
SENSOR_FAILURE = 4,
COMMUNICATION_ERROR = 8
};
private:
DeviceState current_state;
ErrorCode error_flags;
public:
DeviceController()
: current_state(DeviceState::OFF),
error_flags(ErrorCode::NONE) {}
void processState() {
switch (current_state) {
case DeviceState::OFF:
std::cout << "设备已关闭" << std::endl;
break;
case DeviceState::STARTING:
std::cout << "设备启动中..." << std::endl;
// 启动逻辑
if (startSuccessful()) {
current_state = DeviceState::RUNNING;
} else {
current_state = DeviceState::ERROR;
error_flags = static_cast<ErrorCode>(
static_cast<int>(error_flags) |
static_cast<int>(ErrorCode::POWER_FAILURE));
}
break;
case DeviceState::RUNNING:
std::cout << "设备运行中" << std::endl;
monitorOperation();
break;
case DeviceState::STOPPING:
std::cout << "设备停止中..." << std::endl;
performShutdown();
current_state = DeviceState::OFF;
break;
case DeviceState::ERROR:
handleError();
break;
}
}
void setState(DeviceState new_state) {
current_state = new_state;
}
DeviceState getState() const {
return current_state;
}
void addError(ErrorCode error) {
error_flags = static_cast<ErrorCode>(
<"1f.csxthr.com"><"4k.zhaiLimao.com"><"8q.yunruiwater.cn">
static_cast<int>(error_flags) | static_cast<int>(error));
}
void clearError(ErrorCode error) {
error_flags = static_cast<ErrorCode>(
static_cast<int>(error_flags) & ~static_cast<int>(error));
}
bool hasError(ErrorCode error) const {
return (static_cast<int>(error_flags) & static_cast<int>(error)) != 0;
}
std::string getErrorDescription() const {
if (error_flags == ErrorCode::NONE) {
return "无错误";
}
std::string desc;
if (hasError(ErrorCode::OVERHEAT)) {
desc += "过热 ";
}
if (hasError(ErrorCode::POWER_FAILURE)) {
desc += "电源故障 ";
}
if (hasError(ErrorCode::SENSOR_FAILURE)) {
desc += "传感器故障 ";
}
if (hasError(ErrorCode::COMMUNICATION_ERROR)) {
desc += "通信错误 ";
}
return desc;
}
private:
bool startSuccessful() { return true; }
void monitorOperation() {}
void performShutdown() {}
void handleError() {
std::cout << "处理错误: " << getErrorDescription() << std::endl;
}
};
```
## 综合应用:数据序列化框架
```cpp
// 使用结构体、联合体、枚举构建序列化框架
#include <cstring>
#include <vector>
#include <iostream>
// 数据类型枚举
enum class DataType : uint8_t {
INT8 = 0,
INT16,
INT32,
INT64,
FLOAT,
DOUBLE,
STRING,
BOOL,
ARRAY,
STRUCT
};
// 数据值联合体
union DataValue {
int8_t int8_val;
int16_t int16_val;
int32_t int32_val;
int64_t int64_val;
float float_val;
double double_val;
bool bool_val;
// 复杂类型使用指针
struct {
char* str_data;
size_t str_len;
} string_val;
struct {
void* array_data;
size_t array_size;
DataType element_type;
} array_val;
};
// 数据项结构体
struct DataItem {
DataType type;
DataValue value;
std::string name; // 字段名
// 构造函数
DataItem(const std::string& item_name, int32_t val)
: type(DataType::INT32), name(item_name) {
value.int32_val = val;
}
DataItem(const std::string& item_name, double val)
: type(DataType::DOUBLE), name(item_name) {
value.double_val = val;
}
DataItem(const std::string& item_name, const std::string& str)
: type(DataType::STRING), name(item_name) {
value.string_val.str_len = str.length();
value.string_val.str_data = new char[value.string_val.str_len + 1];
strcpy(value.string_val.str_data, str.c_str());
}
DataItem(const std::string& item_name, bool val)
: type(DataType::BOOL), name(item_name) {
value.bool_val = val;
}
// 析构函数(需要清理动态内存)
~DataItem() {
if (type == DataType::STRING && value.string_val.str_data) {
delete[] value.string_val.str_data;
}
else if (type == DataType::ARRAY && value.array_val.array_data) {
// 需要根据element_type清理数组元素
delete[] static_cast<char*>(value.array_val.array_data);
}
}
// 序列化为字节流
std::vector<uint8_t> serialize() const {
std::vector<uint8_t> result;
// 添加类型标记
result.push_back(static_cast<uint8_t>(type));
// 添加数据
switch (type) {
case DataType::INT32:
for (size_t i = 0; i < sizeof(int32_t); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(&value.int32_val)[i]);
}
break;
case DataType::DOUBLE:
for (size_t i = 0; i < sizeof(double); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(&value.double_val)[i]);
}
break;
case DataType::STRING:
// 添加字符串长度
uint32_t len = static_cast<uint32_t>(value.string_val.str_len);
for (size_t i = 0; i < sizeof(uint32_t); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(&len)[i]);
}
// 添加字符串内容
for (size_t i = 0; i < value.string_val.str_len; ++i) {
result.push_back(static_cast<uint8_t>(value.string_val.str_data[i]));
}
break;
case DataType::BOOL:
result.push_back(value.bool_val ? 1 : 0);
break;
// 其他类型处理...
}
return result;
}
// 显示数据
void display() const {
std::cout << name << " = ";
switch (type) {
case DataType::INT32:
std::cout << value.int32_val;
break;
case DataType::DOUBLE:
std::cout << value.double_val;
break;
case DataType::STRING:
std::cout << "\"" << value.string_val.str_data << "\"";
break;
case DataType::BOOL:
std::cout << (value.bool_val ? "true" : "false");
break;
default:
std::cout << "[未知类型]";
break;
}
std::cout << std::endl;
}
};
// 数据包结构体
struct DataPacket {
uint32_t packet_id;
uint32_t timestamp;
std::vector<DataItem> items;
// 序列化整个数据包
std::vector<uint8_t> serialize() const {
std::vector<uint8_t> result;
// 添加包头
for (size_t i = 0; i < sizeof(packet_id); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(&packet_id)[i]);
}
for (size_t i = 0; i < sizeof(timestamp); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(×tamp)[i]);
}
<"2d.sxyicheng.cn"><"5m.jsnjz.cn"><"9r.csxthr.com">
// 添加数据项数量
uint32_t item_count = static_cast<uint32_t>(items.size());
for (size_t i = 0; i < sizeof(item_count); ++i) {
result.push_back(reinterpret_cast<const uint8_t*>(&item_count)[i]);
}
// 添加每个数据项
for (const auto& item : items) {
auto item_data = item.serialize();
result.insert(result.end(), item_data.begin(), item_data.end());
}
return result;
}
void display() const {
std::cout << "=== 数据包 ===" << std::endl;
std::cout << "包ID: " << packet_id << std::endl;
std::cout << "时间戳: " << timestamp << std::endl;
std::cout << "数据项:" << std::endl;
for (const auto& item : items) {
std::cout << " ";
item.display();
}
}
};
// 使用示例
void serialization_framework_demo() {
std::cout << "=== 数据序列化框架演示 ===" << std::endl;
// 创建数据包
DataPacket packet;
packet.packet_id = 1001;
packet.timestamp = 1234567890;
// 添加各种类型的数据项
packet.items.emplace_back("temperature", 25.5);
packet.items.emplace_back("humidity", 60);
packet.items.emplace_back("device_id", "sensor_001");
packet.items.emplace_back("is_active", true);
// 显示数据
packet.display();
// 序列化
auto serialized_data = packet.serialize();
std::cout << "\n序列化大小: " << serialized_data.size() << " 字节" << std::endl;
std::cout << "序列化数据: ";
for (size_t i = 0; i < std::min<size_t>(serialized_data.size(), 20); ++i) {
printf("%02X ", serialized_data[i]);
}
if (serialized_data.size() > 20) {
std::cout << "...";
}
std::cout << std::endl;
}
```
## 性能优化与最佳实践
```cpp
// 结构体打包优化
#pragma pack(push, 1) // 按1字节对齐(紧密打包)
struct NetworkPacket {
uint16_t packet_type; // 2字节
uint32_t sequence_num; // 4字节
uint64_t timestamp; // 8字节
uint8_t data[1024]; // 1024字节
uint16_t checksum; // 2字节
}; // 总共1040字节,无填充
#pragma pack(pop) // 恢复默认对齐
// 使用static_assert检查结构体大小
static_assert(sizeof(NetworkPacket) == 1040,
"NetworkPacket大小应该为1040字节");
// 缓存友好的结构体设计
struct CacheOptimizedEntity {
// 经常一起访问的热数据
int entity_id; // 4字节
float position_x; // 4字节
float position_y; // 4字节
float velocity_x; // 4字节
float velocity_y; // 4字节
uint8_t state_flags; // 1字节
uint8_t : 7; // 7位填充
// 不经常访问的冷数据
char name[32]; // 32字节
char description[128]; // 128字节
// 总共约186字节
// 将热数据打包在一个缓存行(通常64字节)
static constexpr size_t HOT_DATA_SIZE =
sizeof(entity_id) + sizeof(position_x) + sizeof(position_y) +
sizeof(velocity_x) + sizeof(velocity_y) + sizeof(state_flags);
static_assert(HOT_DATA_SIZE <= 64,
"热数据应该适应一个缓存行");
};
// 枚举类的最佳实践
class ConfigManager {
public:
enum class LogLevel : uint8_t {
DEBUG = 0,
INFO,
WARNING,
ERROR,
CRITICAL
};
enum class CacheStrategy : uint8_t {
NONE = 0,
LRU, // 最近最少使用
LFU, // 最不经常使用
FIFO, // 先进先出
RANDOM // 随机替换
};
private:
LogLevel current_log_level;
CacheStrategy cache_strategy;
// 枚举到字符串的转换
static const char* logLevelToString(LogLevel level) {
static const char* names[] = {
"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"
};
return names[static_cast<uint8_t>(level)];
}
static const char* cacheStrategyToString(CacheStrategy strategy) {
switch (strategy) {
case CacheStrategy::NONE: return "NONE";
case CacheStrategy::LRU: return "LRU";
case CacheStrategy::LFU: return "LFU";
case CacheStrategy::FIFO: return "FIFO";
case CacheStrategy::RANDOM: return "RANDOM";
default: return "UNKNOWN";
}
}
public:
void setLogLevel(LogLevel level) {
current_log_level = level;
std::cout << "日志级别设置为: "
<< logLevelToString(level) << std::endl;
}
void setCacheStrategy(CacheStrategy strategy) {
cache_strategy = strategy;
std::cout << "缓存策略设置为: "
<< cacheStrategyToString(strategy) << std::endl;
}
};
```
结构体、联合体和枚举是C++中定义自定义数据类型的基础工具。结构体提供数据聚合,联合体实现内存共享,枚举确保类型安全。这些特性组合使用可以构建复杂的数据结构,同时保持代码的清晰性和类型安全性。通过合理的内存对齐优化和缓存友好的设计,可以显著提升程序性能。掌握这些自定义数据类型的使用,是编写高效、可维护C++代码的重要基础。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3108978/ ,如需转载,请注明出处,否则将追究法律责任。