我开始研究OOAD,但我很难找到C++
代码示例,该示例说明了Association
,Aggregation
和{{ 1}}以编程方式实现。 (到处都有几个帖子,但它们与C#或java有关)。我确实找到了一两个例子,但它们都与我的导师的指示相冲突,我很困惑。
我的理解是:
这就是我实施它的方式:
Composition
这是对的吗?如果没有,那么应该怎么做呢?如果您还给我一本书中的代码参考(以便我可以与我的导师讨论),我们将不胜感激。
答案 0 :(得分:15)
我要忽略聚合。它是not a very clearly defined concept,在我看来,它会导致更多的混乱而不是它的价值。组成和协会已经足够了,Craig Larman告诉我。它可能不是您的教师所寻求的答案,但无论如何都不可能在C ++中实现。
没有一种方法可以实现组合和关联。您如何实施它们将取决于您的要求,例如关系的多样性。
实现组合的最简单方法是使用一个简单的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::shared_ptr
,您可能希望使用std::weak_ptr
} Bar
。
通常使用指针实现关联:
// 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
指针的深层副本实现Aggregation。我不会说这是一个典型的实现,但正如我所说,这取决于您的要求。
您需要确保在delete
析构函数中的bar
成员指针上调用Foo
,否则您有内存泄漏(或使用智能指针)。