0

这个问题在我的考试修订中,我想知道我是否走在正确的轨道上,它来自 C++ 入门教科书。

UML 模型关系如何用 C++ 编码?

公共继承允许您对 IS-A 关系建模,派生类能够重用基类的代码。另一种方法是使用包含,即一个对象拥有或拥有另一个对象的对象之间的关系。这模拟了 HAS-A 关系。

例如:

  • 汽车拥有或拥有马达
  • 当汽车被制造出来的时候,它的马达也被制造出来了
  • 当 Car 被摧毁时,它的马达也被摧毁。

    class Car 
    {
        private:
            Motor *motor;
        public:
            Car()
            { 
                 motor = new Motor(); 
            }
    
            ~Car() 
            { 
                 delete motor; 
            }
    };
    
4

3 回答 3

2

使用 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运算符。

于 2012-10-27T15:38:09.727 回答
1

我不会为您的答案添加太多内容。

就 IS-A 关系而言,公共继承是 C++ 中的工具(但在使用模板时会变得很棘手,并且并不总是按预期工作)。当涉及到 HAS-A 关系时,类成员就是解决方案。更准确地说,我会使用一个Motor motor成员(而不是指针),因为这更加强调了两者之间的关系。就指针而言null,成员将始终被构造和销毁。

HTH,
榆树

于 2012-10-27T15:24:03.513 回答
0

公共继承允许您对 IS-A 关系建模,派生类能够重用基类的代码。

这是一个普遍的误解。继承的重点是不能重用基类的代码而是利用现有的代码来处理提供不同行为的基类。也就是说,至少在 OO 理论中是这样。

C++ 是一种强大的灵活语言,并且没有单一的 UML 到该语言的映射(这就是那些期望从 UML 生成代码的人会一次又一次失败的地方,UML 没有捕获一些细粒度的细节)。

泛化实现都是通过 C++ 中的继承0实现的,尽管在其他语言中它们有所不同。例如,在 Java 中,泛化是通过继承(extends实现的,通过接口实现(implements)实现。

组合这是has-a关系,通常通过类的值成员来实现。请注意,这不是唯一的实现1

聚合可以通过指针2和引用成员来实现,具体取决于其他标准,包括两个对象的相对生命周期以及引用是否可以重置为不同的对象。

使用没有明确建模,而是发生了。使用关系可以出现在接口中(接受或返回不同类型对象的函数使用该类型)或实现(在其定义中使用不同类型的函数——实例化该类型的对象)一些目的)也使用类型。有些人认为这两个是use的不同变体,第一个比第二个更严格,因为它增加了从使用的类型到使用你的类型本身的外部代码的更紧密的耦合。

最后,使用模板还有其他多种选择。例如,语言中的和之间没有关系std::vector<>::iteratorstd::deque<>::iterator但是它们在语言中建模了RandomAccessIterator的概念,而设计为与RandomAccessIterator一起使用的模板可以同时使用它们(例如,std::sort)。std::sort两者都是随机访问迭代器,关系是该概念的泛化,尽管代码中根本不存在(如果他们最终为语言添加了一些概念的味道)。


0)一般来说,我们只会谈论公共继承,但情况并非如此。从不同类型公开继承的类型显然是在泛化/*实现*另一种类型/接口,但这也可以通过私有继承发生。在教授 OO 时不常见的一件事是一个类有两个独立的接口。一方面,有一个公共接口,您类型的用户通过该接口与您的对象进行交互。另一边有一个虚拟的接口,这是您的类型与扩展您的行为的其他类型之间的合同。C++ 中的一个常见习惯用法是 NVI 非虚拟接口,它试图通过强制分离来利用这一点:没有公共虚拟函数意味着公共和虚拟接口是完全隔离的。同样,类型 T 可能没有与基类的公共 is-a关系,尽管在内部它可以将基类的引用或指针传递给其他子系统。对于那些子系统,类型 T基础。可以忽略受保护的继承,因为它被认为是无用的,没有激励性的使用示例。

1)在某些情况下,由其他需求驱动,它可以用指针类型的成员来实现,只要它们在构造时分配并在封闭类型的销毁时释放。在某些情况下,继承被滥用来进行组合和执行大小优化(空基优化)。例如,astd::map可以从比较器继承而不是持有比较器(使用 SFINAE 来检测比较器何时是函子)。如果比较器的类型没有非常频繁的状态,编译器可以将比较器和第一个成员std::map放在同一个内存位置(即比较器不会占用任何空间)。

2)在一般意义上考虑术语指针,包括智能指针。

于 2012-10-27T17:26:11.290 回答