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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:25:38  来源:igfitidea点击:

C++ : Association, Aggregation and Composition

c++oopassociationsaggregationooad

提问by Talha5389

I'm beginning to study OOAD and I'm having difficulty finding a C++code example that'd illustrate how Association, Aggregationand Compositionare 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++即会说明如何代码示例AssociationAggregationComposition通过编程来实现。(到处都有几篇文章,但它们与 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 Barmember variable much like you suggested. The only change I would make is to initialize the barin 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 Barcould be a polymorphic type and you don't know the concrete type at compile time. Or perhaps you want to forward declare Barto 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 Fooshould own the Barand 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_ptrhere because Foois the sole owner of Barbut you might want to use std::shared_ptrif some other object needs a std::weak_ptrto Bar.

我在std::unique_ptr这里使用Foo是因为是 的唯一所有者,Barstd::shared_ptr如果其他对象需要std::weak_ptrto ,您可能想使用它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 Barwill be alive while Foois using it otherwise you have a dangling pointer. If the lifetime of Baris less clear then a std::weak_ptrmay be more appropriate:

当然,你需要确信BarFoo使用它时它会活着,否则你会有一个悬空指针。如果 的生命周期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 Foocan use the Barwithout 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 Baris really unclear an Association could be implemented using a std::shared_ptrbut I think that should be a last resort.

在某些情况下,所有权Bar确实不清楚,可以使用 a 来实现协会,std::shared_ptr但我认为这应该是最后的手段。

Regarding your implementation of Aggregation with a deep copy of a Barpointer. 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 deleteon your barmember pointer in the Foodestructor though otherwise you have a memory leak (or use a smart pointer).

关于您使用Bar指针的深层副本实现聚合。我不会说这是一个典型的实现,但正如我所说,这取决于您的要求。你需要确保你叫delete上你bar的成员指针Foo析构函数虽然否则你有内存泄漏(或者使用智能指针)。