类的重用(包含、嵌套、继承)
大约 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() {}
为嵌套类的构造函数的定义
访问权限与作用域(和普通变量一样)
声明位置 包含它的类是否可以使用它 从包含它的类派生的类是否可以使用它 在外部是否可以使用它 私有部分 是 否 否 保护部分 是 是 否 公有部分 是 是 是,通过类限定符来使用