[英]How are UML model relationships coded in C++?
这个问题在我的考试修订版中,我想知道我是否在正确的轨道上,它来自C ++入门教材。
如何用C ++编码UML模型关系?
公共继承允许您对IS-A关系建模,派生类能够重用基类的代码。 另一种方法是使用包含,即一个对象拥有或拥有另一个对象的对象之间的关系。 这为HAS-A关系建模。
例如:
当Car被破坏时,其电动机也会被破坏。
class Car { private: Motor *motor; public: Car() { motor = new Motor(); } ~Car() { delete motor; } };
使用C ++比使用Java更容易建立组合关系。 在最简单的情况下,包含的对象只是一个值成员:
class Car {
private:
Motor motor;
// No explicit construction/destruction required
};
当您要包含AbstractMotor
的动态类型由调用者使用依赖注入确定时,它会变得更加复杂。 在这种情况下,要对组合进行建模,可以使用unique_ptr
:
class Car {
public:
explicit Car(std::unique_ptr<AbstractMotor> motor): motor(std::move(motor)) { }
private:
std::unique_ptr<AbstractMotor> motor; // Still no explicit destruction required
};
unique_ptr
确保您的Car
是Motor
的唯一所有者,并且Motor
的寿命绑定到Car
对象。
当一个对象拥有另一个对象时,请尝试避免使用原始指针。 使用unique_ptr
,完全不需要实现非平凡的析构函数或使用delete
运算符。
我不会为您的答案增加太多。
就IS-A关系而言, 公开继承是C ++中的工具(尽管使用模板时会很棘手,但并不总是能按预期工作)。 当涉及到HAS-A关系时,类成员就是解决方案。 确切地说,我将使用“ Motor motor
构件(而不是指针),因为这甚至更加强调了两者之间的关系。 并且只要指针可以为null
,就将始终构造并销毁成员。
HTH,
埃尔姆斯
公共继承允许您对IS-A关系建模,派生类能够重用基类的代码。
这是一个普遍的误解。 继承的重点不是能够重用基类的代码,而是利用处理可提供不同行为的基类的现有代码。 也就是说,至少在面向对象理论中。
C ++是一种功能强大的灵活语言,并且没有UML到该语言的单个映射(这是那些期望从UML生成代码的人一次又一次失败的地方,UML无法捕获某些细粒度的细节)。
通用化和实现都是通过C ++中的继承0实现的,尽管在其他语言中它们是不同的。 例如,在Java中, 泛化是通过继承( extends
)来实现的, extends
通过接口实现( implements
)的implements
。
组成这是具有关系的关系,通常通过类的值成员来实现。 请注意,这不是唯一的实现1 。
可以通过指针2和引用成员来实现聚合 ,具体取决于其他条件,包括两个对象的相对生存期以及是否可以将引用重置为其他对象。
使用没有明确建模,而是发生 。 使用关系可以存在于接口中(一个接受或返回不同类型的对象的函数使用该类型),也可以存在于实现中(它的定义中使用不同类型的函数-实例化该类型的对象用于出于某种目的)也使用该类型。 有人认为这两种用法是不同的用法 ,第一种比第二种更为严格,因为它增加了从使用的类型到使用您的类型本身的外部代码的更紧密的耦合。
最后,对于模板,还有多个其他选项。 例如,在该语言中std::vector<>::iterator
和std::deque<>::iterator
之间没有关系,但它们使用该语言对RandomAccessIterator的概念进行了建模,并设计了一个可以正常工作的模板用RandomAccessIterator的可以使用两者(例如, std::sort
从视图的点) std::sort
都是随机访问迭代,所述关系是概念的推广 ,尽管这是不存在的代码在全部(要是他们最终最终在语言中添加了一些概念的味道)。
0)总的来说,我们只会谈论公共继承 ,但事实并非如此。 从其他类型公开继承的类型显然可以概括 / *实现*另一个类型/接口,但是也可以通过私有继承来实现。 教授OO时通常不介绍的一件事是,一个类具有两个单独的接口。 一方面,有一个公共界面,您的类型的用户可以通过该界面与您的对象进行交互。 另一方面,有一个虚拟接口,即您的类型与扩展您的行为的其他类型之间的协定。 C ++中的一个常见习惯是NVI非虚拟接口,它试图通过强制分离来利用这一点:没有公共虚拟函数暗示着公共和虚拟接口是完全隔离的。 以相同的方式,类型T可能没有与基础的公共 is-关系,尽管在内部它可以将对基础类型的引用或指针传递给其他子系统。 对于那些子系统,类型T 是 -base。 受保护的继承可以忽略,因为它没有用处,没有动机。
1)在某些情况下,受其他需求的驱动,可以使用指针类型的成员来实现,只要它们在构造上分配并在破坏封闭类型时释放。 在某些情况下,继承被滥用来进行合成和执行大小优化(空基优化)。 例如,不是持有比较器,而是可以从比较器继承std::map
(使用SFINAE来检测何时比较器是函子)。 如果比较器的类型没有非常频繁的状态,则编译器可以将比较器和std::map
的第一个成员放在相同的内存位置(即比较器将不占用任何空间)。
2)从广义上考虑术语“ 指针” ,其中包括智能指针。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.