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 默认私有,只能通过公有函数读取。

C++ struct 与 class 默认访问运行
#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 语言对齐说明;一般业务代码以可读性优先排列成员。

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。

C++ struct 与 class 默认继承运行
#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 的异同及典型用途。下一节介绍运算符重载:为自定义类型定义 +、<< 等运算。