组合与聚合均为“has-a”关系,核心区别在于部分对象生命周期是否由整体完全控制:组合中成员以值语义内嵌,自动构造析构;聚合通过指针或智能指针持有,生命周期独立;关联则无所有权,仅表长期协作。

组合和聚合都是“has-a”关系,但关键区别在于:**部分对象的生命周期是否由整体对象完全控制**。组合是强拥有,聚合是弱拥有;混淆二者会导致析构逻辑错误、内存泄漏或共享行为异常。
组合:成员对象直接内嵌,自动管理生命周期
组合要求部分类以值语义(非指针/非引用)作为整体类的私有成员。此时 构造函数 中部分类自动构造,析构函数 中自动析构,无需手动干预。
- 常见错误:用
Heart*或std::shared_ptr<heart></heart>声明成员,却声称这是组合 —— 实际已退化为聚合或依赖 - 适用场景:部件与主体不可分离,如
Car与Engine、Human与Heart - 性能影响:无指针间接访问开销,缓存友好;但对象体积增大,拷贝成本高(若未禁用拷贝)
- 示例关键行:
private: Engine engine;(不是Engine* pEngine;)
聚合:通过指针或智能指针持有,生命周期独立
聚合中整体类只持有对部分类的引用(通常是 Shape*、std::shared_ptr<student></student> 等),部分类可被多个整体共享,也可在整体销毁后继续存在。
- 常见错误:用
std::unique_ptr却允许外部转移所有权 —— 这仍是组合语义,不是聚合 - 使用场景:窗口与子控件、班级与学生、文档与段落(段落可被剪切粘贴到其他文档)
- 兼容性注意:若用裸指针,需确保外部不提前释放;用
std::shared_ptr则引入引用计数开销 - 示例关键行:
private: std::vector<student> students;</student>或std::shared_ptr<logger> logger;</logger>
关联:无所有权,仅表示长期协作关系
关联比聚合更松散,通常表现为成员变量是其他类的指针或引用,但不参与其创建/销毁,也不隐含管理意图。它强调“知道对方存在”,而非“拥有对方”。
- 典型错误:把
Friend*成员当作聚合 —— 实际只是关联,因为朋友不属于你,也不能由你析构 - 参数差异:关联常出现在函数参数中(如
void saveTo(Database& db)),也可能是类成员 - 设计信号:如果两个类实例可以互相持有对方指针(双向关联),那基本排除组合/聚合
- 示例:
class Person { private: Person* bestFriend; };——bestFriend的生命周期完全无关
最容易被忽略的是:UML 图里聚合的菱形空心、组合的实心,只是示意;真正决定关系类型的,是代码中 **谁 new / delete、谁调用构造/析构、能否共享指针** —— 而不是变量声明写法表面像不像“包含”。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











