Menu

C++ 结构体教程:把相关数据组合成一个类型

讲解 C++ 结构体:如何把相关的变量打包成一个类型,声明和初始化结构体对象,给结构体加上成员函数和构造函数,以及 struct 和 class 的真正区别。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

为什么要把数据组合在一起

到目前为止,每个变量都是独立的:这里一个 int,那里一个 string。但真实的程序处理的是由多个部分组成的东西:一个点有 x 和 y,一个学生有姓名、年龄和 GPA。把它们当作零散的独立变量传来传去很容易出错:没有任何东西把它们联系在一起,需要这三项的函数就必须接收三个参数。

结构体解决了这个问题。它定义一个新类型,把相关的变量(也就是它的成员)打包成一个整体。定义好之后,你就可以把整个包当作一个值来存储、拷贝和传给函数。

用点运算符访问每个成员(s.name、s.age)。结构体定义的右花括号 } 后面的分号是必需的:漏掉它是 C++ 初学者最常见的编译错误之一。

初始化结构体

逐个给字段赋值可行,但很啰嗦,也容易漏掉某个成员。更简洁的做法是聚合初始化:在花括号里按成员声明的顺序列出各个值。

小心空的默认写法:Point p;(没有花括号)会让 x 和 y 保存垃圾值,因为内置类型的成员不会自动清零。Point p{}; 则会把它们值初始化为 0。优先使用花括号。你也可以直接在定义里写好默认值,这样即使是 Point p; 也能干净地开始:

把结构体作为函数参数

结构体是一个值,所以函数可以只接收一个参数,而不是三个。只是要记住,按值传递结构体会拷贝每一个成员。对于比几个 int 更大的东西,按 const 引用传递来省掉拷贝,这和你在引用一页看到的规则相同。

从函数返回整个结构体,是一次交回多个值的惯用方式,比来回摆弄多个输出引用清楚得多。

添加成员函数和构造函数

结构体不只能装数据。它还可以包含操作自身成员的成员函数,以及在对象创建时就完成初始化的构造函数。到这里,结构体开始像一个带有行为的小对象了。

在成员函数内部,直接用名字访问成员(width、height),它们指的是这个对象自己的那一份。写成 area() const,是告诉编译器这个函数只读取对象,这样你也能在 const Rectangle 值上调用它。构造函数本身就是一个独立的主题,包括 : width(w) 这种初始化列表语法,构造函数那一页会深入讲解。

struct 与 class:真正的区别

你可能听说过“结构体用来装数据,类用来做对象”。这只是一种惯例,并不是语言规则。在 C++ 中,struct 和 class 几乎是同一个东西,唯一内置的区别是默认访问级别。

struct S {
    int x;        // public by default
};

class C {
    int x;        // private by default
};

struct 的成员除非另行标注,否则是 public 的;class 的成员一开始是 private 的。仅此而已:两者都可以有构造函数、成员函数、继承以及其他一切。你甚至可以给结构体加上显式的访问说明符来隐藏成员:

实际的结论:对于每个字段都可以随意访问的透明数据集合(一个 Point、一个 Color、一条配置记录),用 struct;当你想把内部状态藏在公共接口后面加以保护时,用 class。编译器对它们一视同仁,关键字只是表明你的意图。

结构体数组和结构体 vector

因为结构体是普通的类型,你可以把许多个结构体放进数组或 vector 中,像对待其他值一样遍历它们。

注意嵌套的花括号:每个 {"Keyboard", 49.99} 聚合初始化一个 Product,外层花括号则构造整个 vector。在范围循环中使用 const Product&,可以避免每次迭代都拷贝一个结构体:去掉 &,你就会毫无必要地复制每个元素。

下一节:枚举

结构体让你用多个打包在一起的值构建一个类型。下一章则反其道而行:枚举定义的类型只能从一个小的、有名字的集合中取一个值,非常适合 Color::Red、Direction::North 或状态机的状态这类东西。你会看到 enum class 如何提供可读且类型安全的常量,并与你正在构建的结构体和类自然地配合使用。

常见问题

C++ 中的结构体是什么?

struct 是一种用户自定义类型,它把几个相关的变量(称为成员)归到一个名字下。你不必分别管理 string name、int age 和 double gpa 这几个变量,而是把它们打包成一个 Student 类型,然后传递这一个对象即可。结构体也可以包含成员函数和构造函数:在现代 C++ 中,它就是一个成员默认为 public 的完整的类。

C++ 中 struct 和 class 有什么区别?

严格来说,只有默认访问级别不同:除非另行指定,struct 的成员是 public 的,而 class 的成员默认是 private 的。继承也是如此。其他一切,包括构造函数、成员函数、方法和继承,用法完全相同。按照惯例,程序员用 struct 表示单纯的数据集合,用 class 表示带有不变量和隐藏内部实现的类型。

C++ 中如何初始化结构体?

最简单的方法是用花括号按成员顺序进行聚合初始化:Point p{3, 4};。你也可以用点运算符逐个给字段赋值(p.x = 3;),在定义中给成员设置默认值(int x = 0;),或者写一个构造函数让结构体自己完成初始化。推荐使用花括号初始化,因为它不会悄悄地让字段处于未初始化状态。

Coddy 编程语言插图

和 Coddy 一起学编程

开始