C++ 结构体(struct)(一文讲透)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在 C++ 编程中,结构体(struct)是一种用户自定义的数据类型,它允许开发者将多个不同类型的变量组合成一个有意义的整体。对于编程初学者而言,理解结构体的概念是掌握复杂数据组织方式的重要基础;而对中级开发者来说,结构体的高级特性(如内存对齐、继承优化等)能显著提升代码的性能与可维护性。本文将从基础到进阶,结合实际案例,系统讲解 C++ 结构体的使用方法与核心原理。


结构体的定义与基本用法

1. 什么是结构体?

结构体可以类比为一个“数据包裹”:例如快递包裹中可能包含收件人姓名(字符串)、地址(字符串)、包裹重量(浮点数)等多个信息。在 C++ 中,结构体通过将不同类型的数据成员组合在一起,形成一个逻辑上的整体。

语法示例:

struct Student {  
    std::string name;  
    int age;  
    double gpa;  
};  

上述代码定义了一个 Student 结构体,包含三个成员变量:name(字符串类型)、age(整型)、gpa(浮点型)。

2. 结构体的初始化与访问

要使用结构体,需要先声明变量并初始化:

Student alice;  
alice.name = "Alice";  
alice.age = 20;  
alice.gpa = 3.8;  

也可以通过构造函数简化初始化:

Student bob = {"Bob", 21, 3.9};  // 使用大括号初始化  

成员访问的关键字:.->

  • 对于直接访问结构体变量,使用 .
    std::cout << alice.name;  
    
  • 若结构体通过指针访问,则需使用 ->
    Student* ptr = &alice;  
    std::cout << ptr->age;  
    

结构体的内存布局与性能优化

1. 内存对齐(Memory Alignment)

计算机内存以字节为单位,但 CPU 访问数据时更倾向于按“对齐方式”操作。例如,4 字节的整数若存储在地址 0x100(能被 4 整除)处,访问速度更快。结构体的内存布局会自动遵循对齐规则,这直接影响其占用的空间大小。

示例:

struct Misaligned {  
    char a;      // 1 字节  
    int b;       // 4 字节  
    short c;     // 2 字节  
};  

根据默认对齐规则(假设对齐因子为 4),a 占用 1 字节后,CPU 会跳过 3 字节对齐到 0x4 的倍数,b 占用 4 字节,c 后再跳过 2 字节对齐。因此总大小为:
| 成员 | 占用字节 | 对齐后偏移量 |
|------|----------|--------------|
| a | 1 | 0 |
| 空闲 | 3 | 1 → 4 |
| b | 4 | 4 |
| c | 2 | 8 |
| 空闲 | 2 | 10 → 12 |
总大小:12 字节

优化技巧: 通过调整成员顺序或使用 #pragma pack 可减少内存浪费:

#pragma pack(push, 1)  // 设置对齐为 1 字节  
struct Optimized {  
    char a;  
    int b;  
    short c;  
};  
#pragma pack(pop)  

此时总大小为:1 + 4 + 2 = 7 字节


结构体与类的差异

1. 默认访问权限的区别

在 C++ 中,结构体与类的语法几乎相同,但默认访问权限不同:

  • 结构体的成员默认为 public
  • 的成员默认为 private

对比示例:

struct MyStruct {  
    int a;  // public  
};  

class MyClass {  
    int b;  // private  
};  

因此,直接访问 MyStruct 的成员是允许的,而 MyClass::b 需要通过成员函数访问。

2. 结构体更适合“数据容器”

当需要定义纯粹的数据集合(如坐标点、颜色值)时,结构体更直观。例如:

struct Point {  
    float x, y;  
};  

而类通常用于封装复杂行为(如带有方法的 BankAccount 类)。


结构体的高级特性

1. 嵌套结构体

结构体可以包含另一个结构体作为成员,实现多层数据组织:

struct Address {  
    std::string street;  
    std::string city;  
};  

struct Employee {  
    std::string name;  
    Address office;  // 嵌套 Address 结构体  
};  

访问嵌套成员需连续使用 .->

Employee emp;  
emp.office.city = "Shanghai";  

2. 结构体与函数指针

结构体可包含函数指针成员,实现行为的灵活绑定:

struct Calculator {  
    int (*add)(int, int);  // 函数指针成员  
};  

int add_numbers(int a, int b) { return a + b; }  

Calculator calc;  
calc.add = add_numbers;  
int result = calc.add(3, 5);  // 输出 8  

3. 匿名结构体与联合体

匿名结构体可简化代码,但需谨慎使用:

struct {  
    int id;  
    std::string name;  
} user1;  // 直接声明并命名变量  

联合体(union)则允许同一内存区域存储不同数据类型:

union Data {  
    int integer;  
    float floating;  
};  

但同一时间只能存储其中一种类型。


实际应用案例:实现一个简单的“图书管理系统”

1. 需求分析

设计一个图书结构体,包含书名、作者、ISBN 和借阅状态:

struct Book {  
    std::string title;  
    std::string author;  
    std::string isbn;  
    bool is_borrowed;  
};  

2. 核心功能实现

  • 添加书籍

    void addBook(std::vector<Book>& library) {  
        Book new_book;  
        std::cout << "Enter title: ";  
        std::cin >> new_book.title;  
        // ... 其他字段输入  
        library.push_back(new_book);  
    }  
    
  • 借阅功能

    void borrowBook(std::vector<Book>& library, const std::string& isbn) {  
        for (auto& book : library) {  
            if (book.isbn == isbn && !book.is_borrowed) {  
                book.is_borrowed = true;  
                std::cout << "Borrowed successfully!" << std::endl;  
                return;  
            }  
        }  
        std::cout << "Book not found or already borrowed." << std::endl;  
    }  
    

3. 性能优化

若系统需管理数百万本书,可考虑:

  1. 内存对齐优化:确保结构体成员顺序合理,减少填充空间。
  2. 使用轻量级容器:例如 std::array 替代 std::vector(若元素数量固定)。
  3. 缓存局部性:将频繁访问的成员(如 is_borrowed)放在结构体开头,提升 CPU 缓存命中率。

结构体的继承与多态性

虽然结构体默认是 public 继承,但 C++ 允许通过继承扩展结构体的功能。例如:

struct Employee : public Person {  // 继承 Person 结构体  
    int salary;  
    void promote() { salary *= 1.2; }  
};  

但需注意:

  • 结构体继承可能引发内存布局复杂化,需谨慎处理虚函数与多态。
  • 对于需要动态绑定的场景,优先使用类而非结构体。

结论

C++ 结构体是构建复杂数据模型的基础工具。通过合理设计结构体成员、优化内存布局、结合嵌套与函数指针等特性,开发者可以高效地管理数据并提升程序性能。无论是构建简单的数据容器,还是设计面向对象的复杂系统,理解结构体的底层原理与最佳实践,都将显著增强代码的健壮性与可扩展性。

希望本文能帮助读者系统掌握 C++ 结构体的使用,并在实际项目中灵活运用这一强大工具。如需进一步探讨内存对齐优化或结构体的高级用法,欢迎留言交流!

最新发布