C++:关联、聚合和组合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25779394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ : Association, Aggregation and Composition
提问by Talha5389
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.
我开始研究OOAD,我很难找到一个C++
即会说明如何代码示例Association
,Aggregation
并Composition
通过编程来实现。(到处都有几篇文章,但它们与 C# 或 java 相关)。我确实找到了一两个例子,但它们都与我导师的指示相冲突,我很困惑。
My understanding is that in:
我的理解是:
- 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.
- 关联:Foo 有一个指向 Bar 对象的指针作为数据成员
- 聚合:Foo 有一个指向 Bar 对象的指针,并且 Bar 的数据被深度复制到该指针中。
- 组成:Foo 有一个 Bar 对象作为数据成员。
And this is how I've implemented it:
这就是我实现它的方式:
//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)
这样对吗?如果不是,那么应该怎么做呢?如果您还给我参考了书中的代码(以便我可以与我的导师讨论),我将不胜感激
采纳答案by Chris Drew
I'm going to ignore Aggregation. It is not a very clearly defined conceptand in my opinion it causes more confusion than it is worth. Composition and Association are quite enough, Craig Larmantold 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.
我将忽略聚合。这不是一个定义非常明确的概念,在我看来,它会造成比其价值更多的混乱。作曲和联想就足够了,克雷格·拉曼这样告诉我。这可能不是您的讲师正在寻找的答案,但无论如何它不太可能以与 Association 有任何不同的 C++ 实现。
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.
没有一种实现组合和关联的方法。您如何实施它们将取决于您的要求,例如关系的多样性。
Composition
作品
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:
实现组合的最简单方法是使用一个简单的Bar
成员变量,就像您建议的那样。我要做的唯一更改是bar
在构造函数成员初始值设定项列表中初始化 :
// COMPOSITION - with simple member variable
class Foo {
private:
Bar bar;
public:
Foo(int baz) : bar(baz) {}
};
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.
使用构造函数初始化列表初始化成员变量通常是一个好主意,它可以更快,并且在某些情况下,例如 const 成员变量,它是初始化它们的唯一方法。
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:
使用指针实现组合也可能是有原因的。例如,Bar
可能是多态类型,而您在编译时不知道具体类型。或者您可能想要转发声明Bar
以最小化编译依赖性(请参阅PIMPL idiom)。或者这种关系的多重性可能是 1 到 0..1 并且您需要能够有一个 null Bar
。当然,因为这是 CompositionFoo
应该拥有的,Bar
并且在现代 C++11/C++14 世界中,我们更喜欢使用智能指针而不是拥有原始指针:
// COMPOSITION - with unique_ptr
class Foo {
private:
std::unique_ptr<Bar> bar;
public:
Foo(int baz) : bar(barFactory(baz)) {}
};
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
.
我在std::unique_ptr
这里使用Foo
是因为是 的唯一所有者,Bar
但std::shared_ptr
如果其他对象需要std::weak_ptr
to ,您可能想使用它Bar
。
Association
协会
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; }
};
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:
当然,你需要确信Bar
在Foo
使用它时它会活着,否则你会有一个悬空指针。如果 的生命周期Bar
不太清楚,那么 astd::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";
}
};
Now Foo
can use the Bar
without fear of being left with a dangling pointer:
现在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
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
确实不清楚,可以使用 a 来实现协会,std::shared_ptr
但我认为这应该是最后的手段。
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).
关于您使用Bar
指针的深层副本实现聚合。我不会说这是一个典型的实现,但正如我所说,这取决于您的要求。你需要确保你叫delete
上你bar
的成员指针Foo
析构函数虽然否则你有内存泄漏(或者使用智能指针)。