27 章: 模板 和 类层次
2022-06-27 本文已影响0人
my_passion
Note
模板 vs. 类层次
| |
|/ |/
GP OO
(1)
————————————————————————————————————————————————————————————————
模板类 作 接口 | 特例化版本 可 通过 此接口 访问 增加新功能
————————————————————————————————————————————————————————————————
基类 作 接口 | 派生类实现 可 (使用 vf) 通过 此接口 访问 增加新功能
————————————————————————————————————————————————————————————————
(2) 都允许 `1个算法` 只有 `唯一表达`, 但用于 `多种类型` -> `多态`
(3) 组合 `超出两者` 独自所能提供的 `灵活性`
vector<Shape*>
——————————————————————————————————————————
1] 是 `编译时多态 (泛型)` 容器
——————————————————————————————————————————
2] 保存 `运行时多态 (OO) 类层次` 中对象的指针
——————————————————————————————————————————
1) 基类指针 作 模板实参 提供 `运行时多态`
// 3.2.4 节
class Circle: public Shape { /* ... */ };
class Smiley: public Circle
{
private:
vector<Shape*> eyes;
};
2) 模板参数 作 基类(接口) 提供 `类型安全性`
// 26.2.7 来自基类的名字
template <typename T>
class X: public T {/* ... */};
(4) 2者选哪个 ?
1) 运行时效率 & 必须用 `inline`: 只能用 模板; 类层次 靠 ptr/ref, 无法 inline
2) 想用 RTTI: 只能用 类层次; 编译时 无法获知 RTTI
3) 有 层次关系: 优选 类层次
27.1 参数化 和 层次
1 生成类型
(1) Base* p + 数组 -> 坏设计: p[1] 指向的 is not a Shape
void f(Shape* p, int n)
{
for(int i = 0; i != n; ++i)
p[i].draw();
}
void user()
{
Circle image[10];
// ...
f(image, 10);
}
优选 容器 vector
2 模板类型转换
指针模板
表达 所指对象 间
的 继承关系
: 成员模板 用 类型转换运算符
27.2 类模板 层次
模板参数 在类层次中 仅几个函数使用 -> 代码膨胀 -> 优化: 成员模板 -> 优化: 成员指针 指向 模板参数 T 对象(通用接口)
template <typename Color_scheme, typename Canvas>
class Shape;
class Shape
{
template <typename Color_scheme, typename Canvas>
void configure(const Color_scheme&, const Canvas&);
};
1 模板(类) 作 类型安全
的 接口
: 类型转换 交给 compiler
Vector<T*> private 继承 Vector<void*>
template<typename T>
class Vector<T*>: private Vector<void*>
{
public:
using Base = Vector<void*>;
// 类型转换 交给 compiler
T*& operator[](int i)
{
return reinterpret_cast<T*&>(Base:operator[](i) );
}
};
27.3 模板参数 T 作基类: 可接收 UserData 和 Operation
(1) 解决 OO 局限性
[1] 不允许改变 接口基类 中 的类型
[2] 与 inline 函数 相比, vf 调用代价高
1 平衡二叉树 code & UserData 不能硬编码
version1:
Node
模板参数: UserData
Node<UserData> 作 模板实参 传给 Node_base
UserData 提供 小于 < 运算符
version2:
Node
模板参数: UserData & Balance(平衡算法)
Node<UserData, Balance>, Balance 作 模板实参 传给 Node_base
Balance
作 Node_base 基类 (而不是成员) 好处: `空基最优化`
Node_base
模板参数: Node & Balance
version3:
Balance
作 Node_base 显式模板参数 冗长
-> 作 `隐式 模板参数`: Node 的 关联类型 + ADL
template<typename N>
struct Node_base: N::balance_type {/* ... */};
优势: 相比于 用 void*
[1] 类型安全: code 不必 对 void* 类型转换
[2] 高性能: 用 void* 则 无法使用 `基于类型 的 优化技术`
模板类型转换: 指针模板 + 成员模板(类型转换运算符).jpg
模板类型转换: 指针模板 + 成员模板(类型转换运算符) -> 2层 template.jpg
平衡树: 版本1.jpg
平衡树: 版本1.jpg
平衡树: 版本2.jpg
平衡树: 版本3.jpg
平衡树: 版本4.jpg
建议.jpg