C ++:关联,聚合和组合 [英] C++ : Association, Aggregation and Composition
问题描述
我开始研究OOAD,并且很难找到C++
代码示例,该示例说明了如何以编程方式实现Association
,Aggregation
和Composition
. (到处都有几篇文章,但它们与C#或Java有关).我确实找到了一个或两个示例,但是它们都与我的讲师的说明相抵触,我感到困惑.
I'm beginning to study OOAD and I'm having difficulty finding a C++
code example that'd illustrate how Association
, Aggregation
and Composition
are implemented programmatically. (There are several posts everywhere but they relate to C# or java). I did find an example or two, but they all conflict with my instructor's instructions and I'm confused.
我的理解是:
- 关联:Foo拥有一个指向Bar对象作为数据成员的指针
- 聚集:Foo有一个指向Bar对象的指针,并且Bar的数据被深复制到该指针中.
- 组成:Foo有一个Bar对象作为数据成员.
- Association: Foo has a pointer to Bar object as a data member
- Aggregation: Foo has a pointer to Bar object and data of Bar is deep copied in that pointer.
- Composition: Foo has a Bar object as data member.
这就是我的实现方式:
//ASSOCIATION
class Bar
{
Baz baz;
};
class Foo
{
Bar* bar;
void setBar(Bar* _bar)
{
bar=_bar;
}
};
//AGGREGATION
class Bar
{
Baz baz;
};
class Foo
{
Bar* bar;
void setBar(Bar* _bar)
{
bar = new Bar;
bar->baz=_bar->baz;
}
};
//COMPOSTION
class Bar
{
Baz baz;
};
class Foo
{
Bar bar;
Foo(Baz baz)
{
bar.baz=baz;
}
};
这是正确的吗?如果没有,那么应该怎么做呢?如果您还给我提供了一本书中代码的参考(以便我可以与我的老师讨论),将不胜感激
Is this correct? If not, then how should it be done instead? It'd be appreciated if you also give me a reference of a code from a book (so that I can discuss with my instructor)
推荐答案
我将忽略聚合.它不是一个非常明确定义的概念, ,在我看来,这引起了更多的混乱,而不是值得的.组成和关联就足够了, Craig Larman 告诉我.这可能不是您的老师想要的答案,但是无论如何,它都不可能以C ++的方式与Association有所不同.
I'm going to ignore Aggregation. It is not a very clearly defined concept and in my opinion it causes more confusion than it is worth. Composition and Association are quite enough, Craig Larman told me so. It might not be the answer your instructor was looking for but it is unlikely to be implemented in C++ any differently to Association anyway.
没有一种实现组合和关联"的方法.如何实现它们取决于您的要求,例如关系的多重性.
There is not one way of implementing Composition and Association. How you implement them will depend on your requirements, for example the multiplicity of the relationship.
实现合成的最简单方法是使用一个简单的Bar
成员变量,就像您建议的那样.我唯一要做的更改是初始化构造函数成员初始化器列表中的bar
:
The simplest way of implementing composition is using a simple Bar
member variable much like you suggested. The only change I would make is to initialize the bar
in the constructor member initializer list:
// COMPOSITION - with simple member variable
class Foo {
private:
Bar bar;
public:
Foo(int baz) : bar(baz) {}
};
使用构造函数初始化列表初始化成员变量通常是一个好主意,它可以更快,并且在某些情况下,例如const成员变量,这是初始化它们的唯一方法.
It is generally a good idea to initialize member variables using the constructor initialization list, it can be quicker and in some cases like const member variables it is the only way to initialize them.
也可能有使用指针实现合成的原因.例如,Bar
可能是多态类型,而您在编译时不知道具体类型.或者,您可能希望转发声明Bar
以最大程度地减少编译依赖性(请参阅 PIMPL习惯用法).或这种关系的多重性可能是1到0..1,并且您需要能够有一个空的Bar
.当然,因为这是Composition Foo
应该拥有Bar
,并且在C ++ 11/C ++ 14的现代世界中,我们更喜欢使用智能指针而不是原始指针:
There might also be a reason to implement composition using a pointer. For example Bar
could be a polymorphic type and you don't know the concrete type at compile time. Or perhaps you want to forward declare Bar
to minimize compilation dependencies (see PIMPL idiom). Or perhaps the multiplicity of this relationship is 1 to 0..1 and you need to be able to have a null Bar
. Of course because this is Composition Foo
should own the Bar
and in the modern world of C++11/C++14 we prefer to use smart pointers instead of owning raw pointers:
// 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
.
I've used std::unique_ptr
here because Foo
is the sole owner of Bar
but you might want to use std::shared_ptr
if some other object needs a std::weak_ptr
to Bar
.
通常会使用指针来实现关联:
Association would usually be implemented using a pointer as you have done:
// Association - with non-owning raw pointer
class Foo {
private:
Bar* bar;
public:
void setBar(Bar* b) { bar = b; }
};
当然,您需要确信Bar
在使用Foo
时将仍然存在,否则您的指针会悬空.如果Bar
的生存期不太清楚,则std::weak_ptr
可能更合适:
Of course you need to be confident that Bar
will be alive while Foo
is using it otherwise you have a dangling pointer. If the lifetime of Bar
is less clear then a std::weak_ptr
may be more appropriate:
// 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
,而不必担心指针悬空:
Now Foo
can use the Bar
without fear of being left with a dangling pointer:
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
来实现协会,但是我认为这应该是最后的选择.
In some cases where ownership of Bar
is really unclear an Association could be implemented using a std::shared_ptr
but I think that should be a last resort.
关于使用Bar
指针的深层副本进行聚合的实现.我不会说这是典型的实现,但正如我所说,这取决于您的要求.
您确实需要确保在Foo
析构函数中的bar
成员指针上调用delete
,尽管否则会发生内存泄漏(或使用智能指针).
Regarding your implementation of Aggregation with a deep copy of a Bar
pointer. I wouldn't have said that was a typical implementation but, as I said, it depends on your requirements.
You do need to make sure you call delete
on your bar
member pointer in the Foo
destructor though otherwise you have a memory leak (or use a smart pointer).
这篇关于C ++:关联,聚合和组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!