类之间的关系

来源:互联网 发布:网络上表示污的词语 编辑:程序博客网 时间:2024/04/26 06:15

在类之间最常见的关系是

  • 依赖(use-a)
  • 聚合(has-a)也称为复合(composition)
  • 继承(is-a)

表达类关系的UML连接图
表达类关系的UML连接图

在订单处理系统中:
order:订单
Item: 项目
Account:账户

依赖

order类使用Account类,因为必须访问Account对象查看信用状态,但是Item类不依赖于Account类。

聚合(aggregation)或复合(composition)

比如,一个order对象包含一些Item对象
又比如

class Address{...};class PhoneNumber{...};class Person{    public:    ...    private:        std::string name;        Address address;        PhoneNumber voiceNumber;        PhoneNumber  faxNumber;}

(条款38)

继承(is-a)

比如RushOrder类继承自Order类,在RushOrder类中包含一些用于优先处理的特殊方法。

public继承 意味着is-a,适用于base classes身上的每一件事情一定也适用于derived classes身上,因为每一个derived class对象也都是一个base class对象(条款32)

那么private继承呢?
如果classes之间的继承关系是private,那么编译器不会自动将一个derived class对象转换成一个base class对象,这和public继承不同,由private继承的所有成员,在derived class中会变成private属性。

private继承意味着根据某物实现出,如果D以private继承自B,意思是D对象根据B对象实现而得,其意义只及于软件实现层面,没有其他意义。

例如:
我们想要修改Widget class,让它记录每个成员函数被调用的次数,为了完成这项工作,我们需要设定某种定时器,让我们知道收集数据的时候是否到了。

现在有一个类:

 class Timer{    public :        explicit Timer(int tickFrequency);        virtual void onTick() const;};

如果我们让widget重新定义timer内的virtual函数,Widget必须继承自Timer,但是在这里public继承并不恰当,因为它们不是is-a的关系。
我们必须以private的形式继承Timer:

class Widget: private Timer{    private:        virtual void onTick() const;}

但是这样的设计并不是绝对必要的,我们可以用复合的方式取而代之。

 class Widget{    private:        class WidgetTimer: public Timer{        public:            virtual void onTick() const;                ...    };    WidgetTimer timer;}

这个设计同时涉及到public继承和复合,并且导入了一个新的class。

private继承主要用于一个意欲成为derived class者想访问一个意欲成为base class者的protected的成分,或者为了重新定义一个或多个virtual函数,这两个class之间是is-implemented-in-term-of 而非is-a 的关系。
还有一种情况,就是涉及到空间最优化时,可能会让你选择private 继承而不是继承加复合。

class Empty{};class HoldsAnInt{    private:        int x;        Empty e;}

你会发现sizeof(HoldsAnInt)>sizeof(int)

class HoldsAnInt:private Empty{    private:        int x;}

可以确定sizeof(HoldsAnInt)==sizeof(int),这就是空白基类最优化(EBO),这对对象尺寸最小化的程序开发者而言可能很重要(条款39)


资料来源:
Java 核心技术卷 1
Effective C++

0 0