C++ struct 结构体详解

71次阅读
没有评论

本文系统讲解 C++ struct:基础语法与与 class 的差异、初始化与聚合、内存布局与对齐、位域、继承与多态可行性、与 C 的互操作、现代 C++ 特性、最佳实践与常见陷阱。包含可运行示例与构建指令。

目录

  • 结构体基础与语法
  • structclass 的区别
  • 初始化与聚合(Aggregate)
  • 内存布局与对齐(标准布局/POD)
  • 位域(Bit-field)
  • 继承与多态(可行性与影响)
  • 与 C 的互操作
  • 现代 C++ 特性要点
  • 示例与构建
  • 最佳实践与常见陷阱

结构体基础与语法

  • struct 是用户自定义类型,和 class 本质相同,唯一区别是默认访问说明符与继承是 public
  • 成员可包括:数据成员、成员函数(含构造/析构)、静态成员、嵌套类型、类型别名。
  • 作用域解析:StructName::member;头文件声明、源文件实现可分离。

示例:

struct Point {
    int x{0};
    int y{0};
    void move(int dx, int dy) { x += dx; y += dy; }
};

structclass 的区别

  • 默认访问:struct 默认 publicclass 默认 private;除此之外语义完全相同。
  • 风格约定:常将 struct 用于“纯数据载体”(POD/聚合)或轻量对象;class 用于封装更强的类型与不变量。
  • 访问控制:struct 也可显式使用 private/protected,并具有构造、析构、虚函数、继承等能力。

初始化与聚合(Aggregate)

  • 聚合类型:无用户自定义构造、无私有/受保护非静态成员、无虚函数、无基类等条件满足时,struct 为聚合。
  • 聚合初始化:使用花括号按成员顺序初始化,支持 C++20 指定初始化(部分编译器支持有限)。

示例:

struct Color { int r; int g; int b; };
Color c1{255, 128, 64}; // 聚合初始化

内存布局与对齐(标准布局/POD)

  • 标准布局(standard-layout):保证成员顺序与内存布局的可预期性,便于与 C 交互与序列化。
  • POD(Plain Old Data):满足标准布局且平凡(trivial)的类型,支持 C 风格初始化与二进制拷贝。
  • 对齐:类型有对齐要求(alignof(T)),编译器可能插入填充字节(padding)。
  • 观察布局:sizeof(T)offsetof(T, member) 可用于了解大小与偏移。

示例:

#include 
<cstddef>
struct alignas(16) Vec4 { float x,y,z,w; };
static_assert(alignof(Vec4) == 16);
static_assert(sizeof(Vec4) == 16);
size_t offx = offsetof(Vec4, x); // 0

位域(Bit-field)

  • 位域允许以位级粒度定义成员宽度:unsigned flags:3;
  • 注意事项:实现相关的布局与端序、跨平台差异、与 sizeof/offsetof 的交互;常用于嵌入式或协议头。

示例:

struct Header {
    unsigned version:4;
    unsigned type:4;
    unsigned length:16;
};

继承与多态(可行性与影响)

  • struct 可继承与定义虚函数,多态能力与 class 一致;含虚函数会引入虚表指针影响布局。
  • 默认继承是 publicstruct Derived : Base {};当作接口也需虚析构。

示例:

struct Shape { virtual ~Shape() = default; virtual double area() const = 0; };
struct Rect : Shape { double w{}, h{}; double area() const override { return w*h; } };

与 C 的互操作

  • 与 C 接口互通通常需要标准布局且避免 C++ 特性(虚函数、非平凡构造/析构)。
  • 使用 extern "C" 暴露函数名以避免名称修饰;结构体作为数据交换需保证 ABI 兼容。
  • 谨慎使用 #pragma pack 修改对齐;更建议用 alignas 与静态断言校验大小。

示例:

extern "C" {
    struct CPoint { int x; int y; };
    void process_point(struct CPoint* p); // C 风格接口
}
static_assert(std::is_standard_layout
<CPoint>::value, "must be standard layout");

现代 C++ 特性要点

  • =default/=delete:控制特殊成员函数的生成或禁用。
  • constexpr/consteval:编译期常量与编译期计算的结构体方法/构造。
  • [[nodiscard]]:防止忽略关键返回值;noexcept:强异常安全保证与优化提示。
  • 规则(Three/Five/Zero):资源管理最好交由标准容器/智能指针,结构体保持聚合风格。

示例:

struct Config {
    int port{};
    [[nodiscard]] bool valid() const noexcept { return port > 0; }
};

示例与构建

struct_demo.cpp

#include 
<iostream>
#include 
<cstddef>
#include 
<type_traits>

struct Color { int r; int g; int b; };
struct alignas(16) Vec4 { float x,y,z,w; };
struct Header { unsigned version:4; unsigned type:4; unsigned length:16; };

int main() {
    Color c{255,128,64};
    std::cout << c.r << "," << c.g << "," << c.b << "\n";

    Vec4 v{1,2,3,4};
    std::cout << "alignof(Vec4)=" << alignof(Vec4) << ", sizeof(Vec4)=" << sizeof(Vec4) << "\n";
    std::cout << "offsetof(Vec4::x)=" << offsetof(Vec4, x) << "\n";

    Header h{1,2,100};
    std::cout << "version=" << h.version << ", type=" << h.type << ", length=" << h.length << "\n";

    static_assert(std::is_standard_layout
<Color>::value);
    return 0;
}

构建与运行(macOS zsh):

clang++ -std=gnu++20 struct_demo.cpp -o struct_demo
./struct_demo

最佳实践与常见陷阱

  • 用于数据载体时保持聚合特性,避免引入虚函数/私有成员导致失去聚合初始化。
  • 注意填充与对齐,序列化/与 C 交互前用 static_assert(sizeof(T)==预期) 验证。
  • 位域跨平台差异显著;协议头尽量使用显式字节序与序列化函数,不直接依赖位域布局。
  • 初始化顺序与成员声明顺序一致;避免未初始化成员。
  • 与 C 接口交互时避免使用异常、模板、复杂构造;保持标准布局与平凡性。

正文完
 0
评论(没有评论)

YanQS's Blog