在C++中,结构体(struct)是一种用户自定义的复合数据类型,允许将多个不同类型的变量组合成一个整体。通过struct关键字,开发者可以描述现实世界中具有多种属性的对象,比如坐标点、网络数据包头或配置项集合。结构体的引入让函数参数传递更简洁,也方便在数组中批量管理同类数据。

一、struct关键字的基本定义语法
C++里定义一个结构体,最核心的形式就是以struct开头,后面紧跟类型名称,接着是一对花括号,括号内声明各个成员,最后以分号结尾。这种语法从C语言继承而来,但在C++中功能被大幅增强。最基础的例子如下:
struct Point {
int x;
int y;
};
上面代码定义了一个名为Point的结构体类型,它包含两个整型成员x和y。注意结尾的分号不能省略,这是很多初学者容易忽略的地方。定义完成后,就可以像使用内置类型一样声明变量:Point p1; 此时p1拥有x和y两个成员,可通过p1.x和p1.y访问。
在C++中,struct定义本身也是一种类型声明,不需要像C语言那样每次都带struct前缀。也就是说,C语言要写struct Point p;,而C++直接写Point p;即可。此外,结构体内部不仅可以有数据,还能直接定义函数,这是C++对struct的重要扩展。
二、结构体成员函数与访问控制
和class相似,C++的struct支持成员函数,也支持public、private等访问说明符。默认情况下,struct的成员都是public,而class默认是private。这一差异决定了struct更常用于单纯的数据聚合,class用于需要隐藏实现的场景。
struct Rectangle {
int width;
int height;
int area() {
return width * height;
}
};
int main() {
Rectangle r;
r.width = 10;
r.height = 5;
int a = r.area();
return 0;
}
上述代码中,Rectangle结构体除了width和height两个变量,还包含area成员函数,用于计算面积。因为struct默认公开,所以在main函数中可以直接给r.width赋值并调用r.area()。如果换成class,不显式写public就无法在外部访问这些成员。
尽管struct能写复杂的成员函数和私有成员,但工程实践中建议保持struct轻量。若类型需要严格的封装、继承体系或大量业务逻辑,应优先选择class。struct适合作为纯数据传输对象(DTO),比如从文件或网络读取的配置块。
三、结构体的初始化方式
C++为结构体提供了多种初始化手段。最传统的是定义后逐个赋值,也可以使用花括号进行聚合初始化,C++11之后还支持统一初始化语法,甚至能在结构体里写构造函数。
struct Student {
int id;
char name[20];
float score;
};
Student s1 = {1, "Tom", 89.5f};
Student s2{2, "Lucy", 92.0f};
struct Vector3 {
int x, y, z;
Vector3(int a, int b, int c) : x(a), y(b), z(c) {}
};
Vector3 v(1, 2, 3);
第一段使用花括号初始化s1和s2,顺序必须和成员声明一致。第二段展示了在结构体内部定义构造函数,这样就能像调用类一样用Vector3 v(1,2,3);创建对象。构造函数让初始化更灵活,也能顺便做参数校验。
需要注意,如果结构体拥有用户提供的构造函数,聚合初始化(花括号按序赋值)在某些旧标准下会受限;但在C++11及以后,只要构造函数不是explicit且匹配,仍可使用部分初始化特性。为兼容性和可读性考虑,团队应统一一种初始化风格。
四、结构体与class的核心区别
很多C++新手分不清struct和class,其实从语法层面看,二者几乎一模一样,唯一默认区别是成员访问权限和继承方式:struct默认public,class默认private;struct默认公有继承,class默认私有继承。
| 特性 | struct | class |
|---|---|---|
| 默认成员访问 | public | private |
| 默认继承方式 | public | private |
| 典型用途 | 数据聚合 | 封装与行为抽象 |
除了上述默认值差异,struct也能继承、也能有虚函数、也能模板化。选择哪一个更多是基于语义约定:看到struct读者会预期它是“开放的数据包”,看到class会预期它有内部状态和隐藏逻辑。保持这种约定能提升代码可读性。
在底层开发如通信协议解析时,常用struct映射二进制布局,此时要留意内存对齐问题。可用#pragma pack或alignas控制对齐,确保结构体大小和字节顺序符合协议规范,否则跨平台读写会出现错位。
五、常见错误与编写建议
定义结构体时,漏写结尾分号是编译错误的高发区。另外,在C++中把struct名和变量名写重、或在头文件里重复定义而未加#ifndef保护,也会引发链接冲突。推荐把结构体定义放在头文件并配合头文件守卫。
#ifndef MY_STRUCT_H
#define MY_STRUCT_H
struct SensorData {
float temperature;
float humidity;
int timestamp;
};
#endif
如上所示,用宏守卫避免同一结构体被多个源文件包含时重复定义。若结构体需在多个文件共享,应仅声明一次。对于包含指针成员的结构体,要谨慎处理拷贝构造和析构,防止浅拷贝导致双重释放。
总体来看,掌握struct关键字的基本语法是C++入门的扎实一步。从单纯的数据打包,到带函数和构造函数的轻量类型,struct在性能和表达力之间提供了很好的平衡。理清它与class的细微差别,能在设计类型时做出更合理的取舍。