当前位置: 首页 > news >正文

C++中聚合类(Aggregate Class)知识详解和注意事项

一、聚合类(Aggregate Class)概念

  • 聚合(Aggregate) 是 C++ 中一类特殊的类类型,无用户自定义构造函数无私有或受保护非静态数据成员无虚函数无基类(C++11 起基类必须也是聚合且无私有/受保护成员)等。
  • 对聚合类型,可使用 聚合初始化(aggregate initialization):通过花括号 {} 直接按声明顺序对成员进行初始化,无需编写构造函数。

二、C++ 标准中聚合定义演变

标准聚合定义要素
C++98无用户构造函数、无私有/受保护成员、无虚函数、无基类
C++11同 C++98;允许成员带默认初始值
C++17同 C++11;继承自 struct 基类仍可是聚合
C++20放宽:允许有基类、允许有 = default 构造(若符合条件)

三、聚合初始化语法

struct Point { double x, y; };Point p1{1.0, 2.0};         // x=1.0, y=2.0
Point p2 = {3.0, 4.0};     // 等价
Point arr[] = { {0,0}, {1,1}, {2,2} };
  • 按成员声明顺序依次匹配初始值列表。

  • 对于带默认成员初始化的聚合,可只初始化前几个成员,剩余成员用默认值:

    struct S {int a{1};int b{2};int c{3};
    };
    S s1{10};      // a=10, b=2, c=3
    S s2{10,20};   // a=10, b=20, c=3
    S s3{};        // a=1, b=2, c=3
    

四、聚合条件详解

要成为聚合,类必须满足(C++20):

  1. 无用户提供的构造函数(包括 = delete= default
  2. 所有非静态数据成员均为公有
  3. 无虚基类(可以有非虚基类,只要该基类自身也是聚合)
  4. 无虚函数
  5. 无成员初始值设定以外的“专用”初始化
  6. 若有基类,则该基类也必须是聚合,且不含私有/受保护成员

注意:C++20 放宽了对 = default 构造的限制,但如果显式声明了任何构造(即使 = default),则该类不再是聚合。


五、使用聚合的优势

  • 简洁:无需编写繁琐构造函数,即可完成对象初始化。

  • 直观:初始化列表按成员顺序一目了然。

  • 易于与传统 C 风格交互:如 memset、数组初始化等场景。

  • 支持结构化绑定(C++17 起):

    struct P { int x; int y; };
    P p{5,6};
    auto [a,b] = p;  // a=5, b=6
    

六、常见注意事项

  1. 初始化次序

    • 聚合初始化严格按成员声明顺序,即使列表书写顺序乱也按声明顺序匹配。
  2. 禁止多余初始化器

    • 提供的初始值个数不得超过成员总数,否则编译报错:

      Point p{1,2,3}; // ❌ 多余
      
  3. 非聚合类型无法聚合初始化

    • 如含私有成员、用户构造或虚函数,就必须使用显式构造或工厂函数。
  4. 默认成员初始化配合

    • 若聚合成员已在类内提供默认值,聚合初始化可选择性覆盖。
  5. 带有引用成员

    • 引用成员需在初始化列表中提供值,否则报错。

      struct R { int& r; };  
      int x; R rr{x}; // OK
      R rr2{};       // ❌ 引用未初始化
      
  6. 数组成员初始化

    • 支持对数组成员进行聚合初始化:

      struct A { int a[3]; };
      A a{{1,2,3}};
      
  7. 嵌套聚合

    • 嵌套聚合成员也按顺序初始化:

      struct Inner { int i; };
      struct Outer { Inner in; double d; };
      Outer o{{42}, 3.14};
      

七、综合示例

#include <iostream>
#include <string>struct Address {std::string city;int zip;
};struct Person {std::string name;int age{30};           // 默认成员初始化Address     address;double      scores[3];
};int main() {// 全部成员初始化Person p1{"Alice", 25, {"NYC", 10001}, {90.0, 85.5, 92.0}};std::cout << p1.name << ", " << p1.age << ", " << p1.address.city << ", scores[1]=" << p1.scores[1] << "\n";// 部分初始化,age 使用默认Person p2{"Bob", /*age=*/{}, {"LA", 90001}, {}};  // p2.name="Bob", age=30, address.city="LA", zip=90001, scores all=0.0// 结构化绑定(C++17)auto [nm, ag, addr, scrs] = p1;std::cout << "Bound: " << nm << "@" << addr.city << "\n";return 0;
}

八、小结

  • 聚合类是无需编写构造函数即可用 {} 一步初始化所有成员的类型。
  • 随 C++ 标准演进,聚合规则有所放宽,但核心要求仍是“无用户构造、无私有/受保护成员、无虚特性”。
  • 正确利用聚合初始化,能使类型定义更简洁、初始化更直观,但应注意成员声明顺序和默认初始化的配合。
http://www.xdnf.cn/news/539317.html

相关文章:

  • 深入理解动态规划:从斐波那契数列到最优子结构
  • YoloV9改进策略:卷积篇|风车卷积|即插即用
  • 【Python-Day 15】深入探索 Python 字典 (下):常用方法、遍历、推导式与嵌套实战
  • C++容器适配器
  • DAPO:用于指令微调的直接偏好优化解读
  • 【idea 报错:java: 非法字符: ‘\ufeff‘】
  • 第二十一次博客打卡
  • 【C语言内存函数】--memcpy和memmove的使用和模拟实现,memset函数的使用,memcmp函数的使用
  • 1 asyncio模块
  • Ubuntu——配置静态IP
  • 基于Transformers与深度学习的微博评论情感分析及AI自动回复系统
  • 【C++】模版(1)
  • 基于不完美维修的定期检测与备件策略联合优化算法matlab仿真
  • megatron——EP并行
  • 商标名称起好后,尽快申请注册确权!
  • 【cursor疑惑】cursor续杯后使用agent对话时,提示“需要pro或商业订阅的用户才能使用“
  • 电路研究9.3.6——合宙Air780EP中的AT开发指南:FTP 应用指南
  • np.r_的用法
  • 代码随想录 算法训练 Day6:哈希表part1
  • Mybatis的标签:if标签、where标签、choose,when标签、set标签
  • 【vs2022的C#窗体项目】打开运行+sql Server改为mysql数据库+发布
  • React学习———Immer 和 use-immer
  • 编译zstd
  • 《垒球百科全书》垒球是什么·棒球1号位
  • `asyncio.gather()` 是什么
  • 深度强化学习框架DI-engine
  • Java大师成长计划之第27天:RESTful API设计与实现
  • 算法竞赛 Java 高精度 大数 小数 模版
  • MySQL故障排查域生产环境优化
  • IIR 巴特沃斯II型滤波器设计与实现