struct 与 class 在 C++ 中几乎等价,仅默认访问权限不同:struct 成员默认为 public,class 默认为 private。结构体常用于表示若干字段的聚合记录,也可包含成员函数与构造。本节对比二者、说明与 C 结构体 的差异,并介绍聚合初始化与内存布局的入门注意点。
数据聚合
#include <iostream>
#include <string>
struct Student {
std::string name;
int score = 0;
};
int main() {
Student s{"Li", 88};
std::cout << s.name << " " << s.score << std::endl;
return 0;
}C++ 结构体可含非 POD 成员(如 std::string),构造与析构由编译器生成或用户定义;C 结构体不能包含需要构造的 C++ 对象。成员可在类内直接初始化(C++11),未在构造函数中覆盖时生效。
聚合初始化与 designated initializer
按成员声明顺序可用花括号提供初值:
Student a{"Ada", 95};
Student b{}; // name 为空串,score 为 0
Student c{.name = "Bob", .score = 80}; // C++20 指定成员初始化字段顺序与声明顺序不一致时,某些写法可能产生警告;宜保持与结构定义一致,便于阅读。
带方法的 struct
#include <cmath>
struct Vec2 {
double x = 0, y = 0;
double length() const {
return std::sqrt(x * x + y * y);
}
Vec2 operator+(const Vec2& o) const {
return {x + o.x, y + o.y};
}
};与 class 相同,可在 struct 内声明成员函数、静态成员、继承等;选择 struct 多表示以公开数据为主、行为为辅的类型。若需严格隐藏不变量,应改用 class 并将数据设为 private(见封装与访问控制)。
与 class 的选用
应用代码里带状态与行为的类型多用 class;struct 多用于字段公开、几乎没有不变量的小型数据(坐标、配置项、一次传递的记录)。二者能力接近,习惯上 class 更常见,并不是语言规定只能用其中一种。
| 场景 | 常见选择 |
|---|---|
| 不变量需严格保护 | class + private 成员 + 公有接口 |
| 配置项、坐标、键值记录 | struct |
| 继承多态接口 | 通常 class |
标准库 std::pair、tuple | 库定义的聚合或类模板 |
真正的语言差别只有默认访问:下面两个类型字段相同,S 可直接读 n,C 的 n 默认私有,只能通过公有函数读取。
#include <iostream>
struct S {
int n = 1; // 默认 public
};
class C {
int n = 1; // 默认 private
public:
int get() const {
return n;
}
};
int main() {
S s;
std::cout << s.n << "\n";
C c;
std::cout << c.get() << "\n";
// std::cout << c.n; // 取消注释将无法通过编译
return 0;
}输出:
1
1若把 struct 改成 class 且不写 public:,s.n 同样无法通过编译。需要对外公开字段时,class 里显式写 public: 后,效果与 struct 相同。
对齐与 padding
编译器可能在成员之间插入填充字节以满足对齐要求,对象大小可能大于各成员大小之和。对内存布局敏感(网络协议、硬件映射)时须查阅 alignof、offsetof 或C 语言对齐说明;一般业务代码以可读性优先排列成员。
#include <iostream>
struct Example {
char c;
int n;
};
int main() {
std::cout << sizeof(char) + sizeof(int) << "\n";
std::cout << sizeof(Example) << "\n";
return 0;
}输出(常见 64 位平台):
5
8成员大小相加为 5,sizeof(Example) 为 8:char 之后插入 3 字节填充,使 int 落在 4 字节对齐的地址上。
与类、继承的关系
struct 可继承 class 或其它 struct,默认继承方式为 public(class 继承时默认为 private)。下面 PublicChild 能直接读基类的 n;PrivateChild 把基类变成私有,类外不能写 b.n。
#include <iostream>
struct Base {
int n = 1;
};
struct PublicChild : Base {}; // 默认 public 继承
class PrivateChild : Base { // 默认 private 继承
public:
int get() const {
return n;
}
};
int main() {
PublicChild a;
std::cout << a.n << "\n";
PrivateChild b;
std::cout << b.get() << "\n";
// std::cout << b.n; // 取消注释将无法通过编译
return 0;
}输出:
1
1需要公开继承时,在 class 上显式写 class Child : public Base。多态层次仍以 class 与虚函数为主,见继承。
本节说明了 struct 与 class 的异同及典型用途。下一节介绍运算符重载:为自定义类型定义 +、<< 等运算。