ITPub博客

首页 > 应用开发 > IT综合 > C++自定义类型:结构体、联合与枚举深度解析与实践

C++自定义类型:结构体、联合与枚举深度解析与实践

投稿 IT综合 作者:bhluo 时间:2026-01-29 14:32:17 0 删除 编辑

《C++自定义类型:结构体、联合与枚举深度解析与实践》


在C++编程中,自定义类型为数据组织和抽象提供了强大支持。结构体、联合和枚举作为基础的自定义类型,各自有着独特的应用场景和实现原理,理解它们的特性是编写高质量C++代码的关键。


**结构体的基本定义与使用**


结构体是C++中最常用的自定义类型,用于将不同类型的数据组合成一个逻辑单元:


```cpp

#include <iostream>

#include <string>


// 基本结构体定义

struct Person {

    // 数据成员

    std::string name;

    int age;

    double height;

    bool isStudent;

    

    // 成员函数(C++中结构体可以有成员函数)

    void display() const {

        std::cout << "姓名: " << name << std::endl;

        std::cout << "年龄: " << age << std::endl;

        std::cout << "身高: " << height << "cm" << std::endl;

        std::cout << "是否学生: " << (isStudent ? "是" : "否") << std::endl;

    }

    

    // 设置成员值的函数

    void setInfo(const std::string& n, int a, double h, bool s) {

        name = n;

        age = a;

        height = h;

        isStudent = s;

    }

};


// 结构体嵌套示例

struct Address {

    std::string street;

    std::string city;

    std::string postalCode;

    

    void print() const {

        std::cout << street << ", " << city << " " << postalCode;

    }

};


struct Employee {

    Person personInfo;

    Address workAddress;

    std::string employeeId;

    double salary;

    

    void printEmployeeInfo() const {

        std::cout << "员工ID: " << employeeId << std::endl;

        personInfo.display();

        std::cout << "工作地址: ";

        workAddress.print();

        std::cout << std::endl;

        std::cout << "薪资: " << salary << std::endl;

    }

};


void structBasicDemo() {

    // 结构体变量的声明和初始化

    Person p1;  // 默认初始化

    p1.name = "张三";

    p1.age = 25;

    p1.height = 175.5;

    p1.isStudent = false;

    

    // 聚合初始化(C++11及以后)

    Person p2 = {"李四", 30, 180.0, false};

    

    // 列表初始化(推荐)

    Person p3{"王五", 22, 168.5, true};

    

    // 访问成员

    p1.display();

    std::cout << std::endl;

    

    // 结构体数组

    Person team[3] = {

        {"成员1", 25, 175.0, false},

        {"成员2", 28, 180.0, true},

        {"成员3", 30, 168.0, false}

    };

    

    for (int i = 0; i < 3; ++i) {

        team[i].display();

        std::cout << std::endl;

    }

}

```


**结构体的高级特性**


C++11及以后版本为结构体引入了许多增强特性:


```cpp

// 带构造函数的结构体

struct Point {

    double x;

    double y;

    

    // 默认构造函数

    Point() : x(0.0), y(0.0) {}

    

    // 带参数的构造函数

    Point(double xVal, double yVal) : x(xVal), y(yVal) {}

    

    // 拷贝构造函数

    Point(const Point& other) : x(other.x), y(other.y) {

        std::cout << "拷贝构造Point" << std::endl;

    }

    

    // 移动构造函数(C++11)

    Point(Point&& other) noexcept : x(std::move(other.x)), y(std::move(other.y)) {

        std::cout << "移动构造Point" << std::endl;

    }

    

    // 运算符重载

    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;

    }

    

    // 类型转换运算符

    explicit operator std::string() const {

        return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";

    }

    

    // 静态成员

    static Point origin() {

        return Point(0, 0);

    }

    

    // 常量成员函数

    double distanceFromOrigin() const {

        return std::sqrt(x*x + y*y);

    }

};


// 位域结构体(用于硬件编程或协议解析)

struct PacketHeader {

    unsigned int version : 4;    // 4位版本号

    unsigned int type : 2;       // 2位类型

    unsigned int flags : 2;      // 2位标志位

    unsigned int length : 8;     // 8位长度

    unsigned int checksum : 16;  // 16位校验和

};


void packetDemo() {

    PacketHeader header;

    header.version = 2;

    header.type = 1;

    header.flags = 3;

    header.length = 128;

    header.checksum = 0xABCD;

    

    std::cout << "数据包头大小: " << sizeof(header) << " 字节" << std::endl;

}

```


**联合的基本概念与应用**


联合是一种特殊的数据结构,所有成员共享同一块内存空间:


```cpp

#include <cstring>


// 基本联合定义

union Data {

    int intValue;

    double doubleValue;

    char stringValue[20];

    

    // C++11起,联合可以有构造函数和成员函数

    Data() : intValue(0) {}  // 必须初始化一个成员

    

    void setInt(int val) {

        intValue = val;

    }

    

    void setDouble(double val) {

        doubleValue = val;

    }

    

    void setString(const char* str) {

        strncpy(stringValue, str, sizeof(stringValue) - 1);

        stringValue[sizeof(stringValue) - 1] = '\0';

    }

};


// 带类型标记的联合(推荐模式)

struct TaggedUnion {

    enum class Type { INT, DOUBLE, STRING };

    Type currentType;

    

    union {

        int intValue;

        double doubleValue;

        char stringValue[50];

    };

    

    TaggedUnion() : currentType(Type::INT) {

        intValue = 0;

    }

    

    ~TaggedUnion() {

        // 如果当前存储的是字符串,需要显式调用析构

        if (currentType == Type::STRING) {

            // 对于简单类型,可以不处理

        }

    }

    

    void setInt(int val) {

        currentType = Type::INT;

        intValue = val;

    }

    

    void setDouble(double val) {

        currentType = Type::DOUBLE;

        doubleValue = val;

    }

    

    void setString(const char* str) {

        currentType = Type::STRING;

        strncpy(stringValue, str, sizeof(stringValue) - 1);

        stringValue[sizeof(stringValue) - 1] = '\0';

    }

    

    void print() const {

        switch (currentType) {

            case Type::INT:

                std::cout << "整数: " << intValue << std::endl;

                break;

            case Type::DOUBLE:

                std::cout << "浮点数: " << doubleValue << std::endl;

                break;

            case Type::STRING:

                std::cout << "字符串: " << stringValue << std::endl;

                break;

        }

    }

};


// 匿名联合(在结构体或类内部)

struct VariantValue {

    enum ValueType { INT, FLOAT, CHAR };

    ValueType type;

    

    union {

        int intVal;

        float floatVal;

        char charVal;

    };

    

    VariantValue(int v) : type(INT), intVal(v) {}

    VariantValue(float v) : type(FLOAT), floatVal(v) {}

    VariantValue(char v) : type(CHAR), charVal(v) {}

};


void unionDemo() {

    Data data;

    

    // 存储不同类型的数据

    data.setInt(10);

    std::cout << "整数: " << data.intValue << std::endl;

    

    data.setDouble(3.14);

    std::cout << "浮点数: " << data.doubleValue << std::endl;

    

    data.setString("Hello");

    std::cout << "字符串: " << data.stringValue << std::endl;

    

    // 注意:只能正确访问最后一次赋值的成员

    std::cout << "\n带类型标记的联合使用:" << std::endl;

    

    TaggedUnion tagged;

    tagged.setInt(42);

    tagged.print();

    

    tagged.setDouble(2.718);

    tagged.print();

    

    tagged.setString("联合示例");

    tagged.print();

    

    // 计算大小

    std::cout << "\nData大小: " << sizeof(Data) << " 字节" << std::endl;

    std::cout << "TaggedUnion大小: " << sizeof(TaggedUnion) << " 字节" << std::endl;

}

```


**枚举类型详解**


枚举提供了类型安全的常量定义方式:


```cpp

// 传统C风格枚举

enum Color {

    RED,    // 0

    GREEN,  // 1

    BLUE,   // 2

    YELLOW = 10,  // 可以指定值

    PURPLE  // 11

};


// 作用域枚举(C++11引入,推荐使用)

enum class TrafficLight {

    RED,    // TrafficLight::RED

    YELLOW,

    GREEN

};


// 指定底层类型的枚举

enum class FileStatus : uint8_t {

    OK = 0,

    NOT_FOUND = 1,

    ACCESS_DENIED = 2,

    IO_ERROR = 3

};


// 带操作的枚举

enum class Month : int {

    JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE,

    JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER

};


// 为枚举定义操作函数

Month nextMonth(Month current) {

    int next = static_cast<int>(current) + 1;

    if (next > 12) next = 1;

    return static_cast<Month>(next);

}


std::string monthToString(Month month) {

    switch (month) {

        case Month::JANUARY: return "一月";

        case Month::FEBRUARY: return "二月";

        case Month::MARCH: return "三月";

        case Month::APRIL: return "四月";

        case Month::MAY: return "五月";

        case Month::JUNE: return "六月";

        case Month::JULY: return "七月";

        case Month::AUGUST: return "八月";

        case Month::SEPTEMBER: return "九月";

        case Month::OCTOBER: return "十月";

        case Month::NOVEMBER: return "十一月";

        case Month::DECEMBER: return "十二月";

        default: return "未知";

    }

}


void enumDemo() {

    // 传统枚举

    Color c = RED;

    int colorValue = c;  // 可以隐式转换为int

    

    std::cout << "颜色值: " << colorValue << std::endl;

    

    // 作用域枚举

    TrafficLight light = TrafficLight::RED;

    // int lightValue = light;  // 错误:不能隐式转换

    int lightValue = static_cast<int>(light);  // 需要显式转换

    

    std::cout << "交通灯值: " << lightValue << std::endl;

    

    // 枚举使用示例

    std::cout << "\n月份枚举示例:" << std::endl;

    

    Month current = Month::JANUARY;

    for (int i = 0; i < 12; ++i) {

        std::cout << static_cast<int>(current) << ": " 

                  << monthToString(current) << std::endl;

        current = nextMonth(current);

    }

    

    // 文件状态枚举示例

    FileStatus status = FileStatus::OK;

    

    switch (status) {

        case FileStatus::OK:

            std::cout << "文件操作成功" << std::endl;

            break;

        case FileStatus::NOT_FOUND:

            std::cout << "文件未找到" << std::endl;

            break;

        case FileStatus::ACCESS_DENIED:

            std::cout << "访问被拒绝" << std::endl;

            break;

        case FileStatus::IO_ERROR:

            std::cout << "IO错误" << std::endl;

            break;

    }

}

```


**复合类型实战应用**


```cpp

// 数据库记录模拟

struct DatabaseRecord {

    enum class RecordType { USER, PRODUCT, ORDER };

    

    RecordType type;

    uint64_t id;

    time_t createdAt;

    time_t updatedAt;

    

    union {

        struct {

            char username[32];

            char email[64];

            uint8_t age;

        } user;

        

        struct {

            char name[64];

            double price;

            uint32_t stock;

        } product;

        

        struct {

            uint64_t userId;

            uint64_t productId;

            uint32_t quantity;

            double totalPrice;

        } order;

    } data;

    

    // 工厂方法

    static DatabaseRecord createUser(uint64_t id, const char* username, 

<"sas.j9k5.org.cn"><"vnd.j9k5.org.cn"><"dsn.j9k5.org.cn"><"abb.j9k5.org.cn">

                                    const char* email, uint8_t age) {

        DatabaseRecord record;

        record.type = RecordType::USER;

        record.id = id;

        record.createdAt = record.updatedAt = time(nullptr);

        

        strncpy(record.data.user.username, username, 

                sizeof(record.data.user.username) - 1);

        strncpy(record.data.user.email, email, 

                sizeof(record.data.user.email) - 1);

        record.data.user.age = age;

        

        return record;

    }

    

    void print() const {

        std::cout << "ID: " << id << std::endl;

        std::cout << "类型: ";

        

        switch (type) {

            case RecordType::USER:

                std::cout << "用户" << std::endl;

                std::cout << "用户名: " << data.user.username << std::endl;

                std::cout << "邮箱: " << data.user.email << std::endl;

                std::cout << "年龄: " << static_cast<int>(data.user.age) << std::endl;

                break;

                

            case RecordType::PRODUCT:

                std::cout << "产品" << std::endl;

                std::cout << "名称: " << data.product.name << std::endl;

                std::cout << "价格: " << data.product.price << std::endl;

                std::cout << "库存: " << data.product.stock << std::endl;

                break;

                

            case RecordType::ORDER:

                std::cout << "订单" << std::endl;

                std::cout << "用户ID: " << data.order.userId << std::endl;

                std::cout << "产品ID: " << data.order.productId << std::endl;

                std::cout << "数量: " << data.order.quantity << std::endl;

                std::cout << "总价: " << data.order.totalPrice << std::endl;

                break;

        }

        

        std::cout << "创建时间: " << ctime(&createdAt);

        std::cout << "更新时间: " << ctime(&updatedAt);

    }

};


// 网络协议数据包解析

struct NetworkPacket {

    enum class PacketType : uint8_t {

        DATA = 0x01,

        ACK = 0x02,

        NAK = 0x03,

        CONTROL = 0x04

    };

    

    struct Header {

        uint16_t packetId;

        PacketType type;

        uint16_t length;

        uint32_t checksum;

    };

    

    Header header;

    

    // 变长数据部分

    union {

        struct {

            uint32_t sequenceNumber;

            char data[1];  // 灵活数组成员(C99特性,C++需特殊处理)

        } dataPacket;

        

        struct {

            uint32_t ackNumber;

            uint32_t windowSize;

        } ackPacket;

        

        struct {

            uint8_t command;

            uint8_t parameters[16];

        } controlPacket;

    };

    

    // 创建数据包

    static NetworkPacket* createDataPacket(uint16_t id, uint32_t seqNum, 

                                          const char* data, uint16_t dataLen) {

        size_t packetSize = sizeof(NetworkPacket) + dataLen;

        auto* packet = reinterpret_cast<NetworkPacket*>(new char[packetSize]);

        

        packet->header.packetId = id;

        packet->header.type = PacketType::DATA;

        packet->header.length = sizeof(Header) + sizeof(uint32_t) + dataLen;

        packet->dataPacket.sequenceNumber = seqNum;

        

        if (dataLen > 0) {

            memcpy(packet->dataPacket.data, data, dataLen);

        }

        

        // 计算校验和

        packet->header.checksum = calculateChecksum(packet);

        

        return packet;

    }

    

private:

    static uint32_t calculateChecksum(const NetworkPacket* packet) {

        // 简单的校验和计算示例

        uint32_t sum = 0;

        const uint8_t* bytes = reinterpret_cast<const uint8_t*>(packet);

        

        for (size_t i = 0; i < packet->header.length; ++i) {

            sum += bytes[i];

        }

        

        return sum;

    }

};

```


**内存布局与性能优化**


```cpp

#include <iomanip>


struct MemoryLayoutDemo {

    // 未优化的结构体

    struct Unoptimized {

        bool flag1;     // 1字节

        int value;      // 4字节

        bool flag2;     // 1字节

        double amount;  // 8字节

        char code;      // 1字节

    };

    

    // 优化后的结构体(考虑内存对齐)

    struct Optimized {

        double amount;  // 8字节

        int value;      // 4字节

        bool flag1;     // 1字节

        bool flag2;     // 1字节

        char code;      // 1字节

        // 编译器可能在这里插入填充字节

    };

    

    // 使用编译指示控制对齐

    #pragma pack(push, 1)  // 1字节对齐

    struct Packed {

        bool flag1;

        int value;

        bool flag2;

        double amount;

        char code;

    };

    #pragma pack(pop)      // 恢复默认对齐

    

    static void demonstrate() {

        std::cout << "内存布局分析:" << std::endl;

        std::cout << "=" << 30 << std::endl;

        

        std::cout << "Unoptimized 大小: " << sizeof(Unoptimized) << " 字节" << std::endl;

        std::cout << "Optimized   大小: " << sizeof(Optimized) << " 字节" << std::endl;

        std::cout << "Packed      大小: " << sizeof(Packed) << " 字节" << std::endl;

        

        // 显示成员偏移

        std::cout << "\n成员偏移(以字节为单位):" << std::endl;

        std::cout << std::setw(20) << "结构体" 

                  << std::setw(10) << "flag1" 

                  << std::setw(10) << "value" 

                  << std::setw(10) << "flag2" 

                  << std::setw(10) << "amount" 

                  << std::setw(10) << "code" << std::endl;

        

        std::cout << std::setw(20) << "Unoptimized"

                  << std::setw(10) << offsetof(Unoptimized, flag1)

                  << std::setw(10) << offsetof(Unoptimized, value)

                  << std::setw(10) << offsetof(Unoptimized, flag2)

                  << std::setw(10) << offsetof(Unoptimized, amount)

                  << std::setw(10) << offsetof(Unoptimized, code) << std::endl;

        

        std::cout << std::setw(20) << "Optimized"

                  << std::setw(10) << offsetof(Optimized, flag1)

                  << std::setw(10) << offsetof(Optimized, value)

                  << std::setw(10) << offsetof(Optimized, flag2)

                  << std::setw(10) << offsetof(Optimized, amount)

                  << std::setw(10) << offsetof(Optimized, code) << std::endl;

    }

};

```


**现代C++特性应用**


```cpp

// C++17结构化绑定

struct Rectangle {

    double width;

    double height;

    

    std::pair<double, double> getDimensions() const {

        return {width, height};

    }

};


void structuredBindingDemo() {

    Rectangle rect{10.0, 20.0};

    

    // C++17结构化绑定

    auto [w, h] = rect.getDimensions();

    std::cout << "宽度: " << w << ", 高度: " << h << std::endl;

    

    // 用于枚举类型

    enum class RGB { RED, GREEN, BLUE };

    std::tuple<RGB, int, std::string> colorInfo{RGB::GREEN, 255, "绿色"};

    <"avg.j9k5.org.cn"><"avr.j9k5.org.cn"><"evs.j9k5.org.cn">

    auto [color, value, name] = colorInfo;

    std::cout << "颜色: " << static_cast<int>(color) 

              << ", 值: " << value 

              << ", 名称: " << name << std::endl;

}


// 使用using定义类型别名(C++11)

using UserId = uint64_t;

using Timestamp = time_t;


struct UserRecord {

    UserId id;

    std::string name;

    Timestamp registrationDate;

    

    // 使用auto返回类型(C++14)

    auto getAgeInDays() const {

        time_t now = time(nullptr);

        return difftime(now, registrationDate) / (60 * 60 * 24);

    }

};


// constexpr结构体(C++11)

struct Circle {

    double radius;

    

    constexpr Circle(double r) : radius(r) {}

    

    constexpr double getArea() const {

        return 3.141592653589793 * radius * radius;

    }

    

    constexpr double getCircumference() const {

        return 2 * 3.141592653589793 * radius;

    }

};


void compileTimeDemo() {

    // 编译时计算

    constexpr Circle unitCircle(1.0);

    constexpr double area = unitCircle.getArea();

    constexpr double circumference = unitCircle.getCircumference();

    

    std::cout << "单位圆面积: " << area << std::endl;

    std::cout << "单位圆周长: " << circumference << std::endl;

}

```


**最佳实践总结**


1. **结构体使用建议**:

   - 对于简单数据聚合,使用struct而非class

   - 合理组织成员顺序以优化内存布局

   - 为复杂结构体提供构造函数和验证逻辑

   - 考虑使用constexpr实现编译时计算


2. **联合使用场景**:

   - 内存敏感型应用,需要节省空间

   - 协议解析和硬件寄存器访问

   - 实现变体类型(配合类型标记)

   - 注意:同一时刻只能使用一个成员


3. **枚举最佳实践**:

   - 优先使用enum class而非传统enum

   - 为枚举指定明确的底层类型

   - 为枚举提供辅助函数(如toString)

   - 避免枚举值隐式转换


4. **性能与安全**:

   - 注意结构体填充和内存对齐

   - 使用编译指示控制打包(如#pragma pack)

   - 确保联合访问的安全性(使用类型标记)

   - 考虑缓存友好性,将相关数据放在一起


5. **现代C++特性**:

   - 使用auto和decltype简化代码

   - 应用结构化绑定处理多返回值

   - 利用constexpr实现编译时计算

   - 使用using代替typedef定义类型别名


结构体、联合和枚举作为C++基础类型系统的延伸,为数据组织提供了强大而灵活的工具。理解它们的特性和适用场景,能够帮助开发者编写出更高效、更安全、更易维护的代码。在实际应用中,应根据具体需求选择最合适的类型,并遵循最佳实践原则。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3109385/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    934283