C++:关联、聚合和组合
Posted
技术标签:
【中文标题】C++:关联、聚合和组合【英文标题】:C++ : Association, Aggregation and Composition 【发布时间】:2014-11-04 22:15:17 【问题描述】:我开始研究 OOAD,但我很难找到一个 C++
代码示例来说明如何以编程方式实现 Association
、Aggregation
和 Composition
。 (到处都有几篇文章,但它们与 C# 或 java 有关)。我确实找到了一两个例子,但它们都与我导师的指示相冲突,我很困惑。
我的理解是:
关联: Foo 有一个指向 Bar 对象的指针作为数据成员 聚合: Foo 有一个指向 Bar 对象的指针,并且 Bar 的数据被深度复制到该指针中。 组合: Foo 有一个 Bar 对象作为数据成员。这就是我实现它的方式:
class Bar
Baz baz;
;
//ASSOCIATION (with Bar)
class Foo
Bar* bar;
void setBar(Bar* _bar)
bar = _bar;
;
//AGGREGATION (with Bar)
class Foo
Bar* bar;
void setBar(Bar* _bar)
bar = new Bar;
bar->baz = _bar->baz;
;
//COMPOSTION (with Bar)
class Foo
Bar bar;
Foo(Baz baz)
bar.baz = baz;
;
这是正确的吗?如果没有,那么应该如何做呢?如果您还可以给我参考书中的代码,将不胜感激(以便我可以与我的导师讨论)
【问题讨论】:
programmers.stackexchange.com 更适合回答这个问题。 聚合和关联的区别is subtle和它们在c++中的实现方式一般是一样的。 我记得我在学校时对同样的术语感到非常困惑。然后,当我进入工作团队时,用于讨论对象关系的唯一术语是 is-a、has-a、继承和组合。也就是说,我知道 UML 有不同的聚合和组合符号,但我从未真正见过有人区分这两者。所以,在你的课程中找到答案,让你得到正确的答案,但不要过分强调。 【参考方案1】:我将忽略聚合。它是not a very clearly defined concept,在我看来,它引起的混乱比它的价值还要多。作文和联想就够了,Craig Larman 这么告诉我的。这可能不是您的讲师正在寻找的答案,但无论如何它不太可能在 C++ 中与 Association 有任何不同。
没有一种方法可以实现组合和关联。您如何实现它们将取决于您的要求,例如关系的多样性。
作曲
实现组合的最简单方法是使用一个简单的Bar
成员变量,就像您建议的那样。我要做的唯一改变是在构造函数成员初始化列表中初始化bar
:
// COMPOSITION - with simple member variable
class Foo
private:
Bar bar;
public:
Foo(int baz) : bar(baz)
;
使用构造函数初始化列表来初始化成员变量通常是一个好主意,它可以更快,并且在某些情况下,例如 const 成员变量,它是初始化它们的唯一方法。
使用指针实现组合也可能是有原因的。例如Bar
可能是多态类型,而您在编译时不知道具体类型。或者您可能想要转发声明Bar
以最小化编译依赖(参见PIMPL idiom)。或者这种关系的多重性可能是 1 到 0..1,并且您需要能够拥有一个空 Bar
。当然,因为这是 Composition Foo
应该拥有 Bar
而在现代 C++11/C++14 世界中,我们更喜欢使用智能指针而不是拥有原始指针:
// COMPOSITION - with unique_ptr
class Foo
private:
std::unique_ptr<Bar> bar;
public:
Foo(int baz) : bar(barFactory(baz))
;
我在这里使用了std::unique_ptr
,因为Foo
是Bar
的唯一所有者,但如果其他对象需要std::weak_ptr
到Bar
,您可能希望使用std::shared_ptr
。
联想
关联通常会像您所做的那样使用指针来实现:
// Association - with non-owning raw pointer
class Foo
private:
Bar* bar;
public:
void setBar(Bar* b) bar = b;
;
当然,您需要确信Bar
会在Foo
使用它时仍然存在,否则您会有一个悬空指针。如果Bar
的生命周期不太清楚,那么std::weak_ptr
可能更合适:
// Association - with weak pointer
class Foo
private:
std::weak_ptr<Bar> bar;
public:
void setBar(std::weak_ptr<Bar> b) bar = std::move(b);
void useBar()
auto b = bar.lock();
if (b)
std::cout << b->baz << "\n";
;
现在Foo
可以使用Bar
而不必担心留下悬空指针:
Foo foo;
auto bar = std::make_shared<Bar>(3);
foo.setBar(bar);
foo.useBar(); // ok
foo.useBar(); // bar has gone but it is ok
在Bar
的所有权确实不清楚的某些情况下,可以使用std::shared_ptr
实现关联,但我认为这应该是最后的手段。
关于使用Bar
指针的深层副本实现聚合。我不会说这是一个典型的实现,但正如我所说,这取决于您的要求。
您确实需要确保在Foo
析构函数中的bar
成员指针上调用delete
,否则会出现内存泄漏(或使用智能指针)。
【讨论】:
以上是关于C++:关联、聚合和组合的主要内容,如果未能解决你的问题,请参考以下文章