跳至主要內容

类的重用(包含、嵌套、继承)

LincZero大约 3 分钟

类的重用(包含、嵌套、继承)

思想

继承关系

is-a(是)/is-a-kind-of(是一种)

  • 描述:is-a关系,即派生类对象也是一个基类对象,可以对基类对象执行的任何操作也可以对派生类对象执行
  • 举例:香蕉是水果
  • 实现:is-a最常用,也是使用最常用的公有继承实现
  • 补充:这种关系称为is-a-kind-of更准确,但通常使用属于is-a

has-a(包括有)

  • 举例:午餐中包括米饭,但米饭不是午餐
  • 实现:一般将一个对象作为另一个的数据成员(包含),或使用私有继承
  • 不能实现:公有继承不能建立这种关系

is-like-a(像一种)

  • 举例:律师像鲨鱼,但律师不是鲨鱼
  • 不能实现:公有继承不能建立这种关系

is-implemented-as-a(作为...来实现)

  • 举例:可以用数组来实现栈,但栈不是数组
  • 不能实现:公有继承不能建立这种关系

uses-a(使用)

  • 举例:计算机可以使用激光打印机
  • 实现:可以使用友元函数或友元类
  • 不能实现:公有继承不能建立这种关系

比较(has-a关系,包含和私有继承区别与选择)

区别

  • 初始化基类组件
    • 包含:创建类的实例对象
    • 私有继承:构造函数需要使用成员初始化列表来构造基类对象
  • 访问基类的方法
    • 包含:使用对象名和句点运算符调用方法,如m_a.fn();
    • 私有继承:使用类名和作用域解析运算符来调用方法,如A::fn();
  • 访问基类对象(使用基类对象本身)
    • 包含:返回对象成员即可,如return m_a;
    • 私有继承:使用强制类型转换(派生类转换为基类)再返回,如return (const APerent &) *this;
  • 访问基类的友元函数
    • 包含:直接使用,如cout m_a;
    • 私有继承:使用强制类型转换(派生类转换为基类)再使用,如cout << (const APerent &) a;

选择

  • 总结
    • 通常使用包含来建立has-a关系
    • 如果新类需要访问原有类的保护成员,或需要重新定义虚函数时,使用私有继承
  • 选用包含:大多数C++程序员倾向于使用包含
    • 包含易于理解、而继承较为抽象
    • 继承会引发很多问题,比如多重继承的一些问题
    • 包含能包括多个同类的子对象,而继承只能使用一个这样的对象
  • 选用私有继承:私有继承提供的特性更多
    • 私有继承可以访问保护成员
    • 可以重新定义基类中的虚函数(非虚函数也能定义,但如果通过引用来调用则会引发问题,不建议修改非虚函数)

嵌套类(类 x 类)

  • 简概

    • 通过新的类型类作用域类避免名称混乱
    • 旧版本的C++不允许嵌套类或无法完全实现这种概念
  • 嵌套类与包含类区别

    • 包含:将类对象作为另一个类的成员
    • 嵌套:不创建类成员,而是定义一种类型,而且该类型仅在包含嵌套类声明的类中有效
  • 使用场景

    • 通常是为了帮助实现另一个类,并避免名称冲突
  • 使用

    • 声明:class中正常嵌套另一个class声明即可
    • 定义:使用两次作用域解析运算符,如Queue::Node::Node() {}为嵌套类的构造函数的定义
  • 访问权限与作用域(和普通变量一样)

    • 声明位置包含它的类是否可以使用它从包含它的类派生的类是否可以使用它在外部是否可以使用它
      私有部分
      保护部分
      公有部分是,通过类限定符来使用