继承
- 派生类必须使用类的派生列表指出是从哪个基类继承
- c++之中使用基类的引用或者指针调用一个虚函数时将发生动态绑定
- 派生类需要对需要使用的继承而来的虚函数进行新定义以覆盖旧的定义(override)
继承和静态成员
- 基类定义了静态成员,整个继承体系之中只存在该成员的唯一定义
- 静态成员遵从通用的访问控制规则
- 如果静态成员时可访问的,则可以通过基类和派生类访问
防止继承发生
- c++11关键字final
静态类型和动态类型
- 静态类型在编译阶段已知,他是变量声明时或者表达式生成的类型
- 动态类型是变量或表达式表示的内存中的对象的类型,运行时才可知
存在继承关系类型之间的转换规则
- 基类向派生类不存在隐式类型转换
- 从派生类向积累类的类型转换只对指针或者引用有效
- 派生类向基类的转换可能会由于访问受限而不可行
c++的多态性
多态性的根本
- 引用或指针的静态类型与动态类型不同是c++语言支持多态性的根本
- 对非虚函数调用在编译时确定绑定
- 通过对象进行的函数调用将在编译时绑定到该对象所属类中的函数版本上
- 当且仅当通过指针或者引用调用虚函数时,才会在运行时解析该调用
虚函数
- 含有纯虚函数的类时抽象基类
- 成员函数无论是否时虚函数都能被重载
- 析构函数一般为虚函数
- 如果基类的析构函数不是虚函数,则delete一个指向派生类对象的基类指针将产生未定义的行为
- 当派生类定义了拷贝或移动操作时,该操作负责拷贝或者移动包括基类部分成员在内的整个对象
- 默认情况下,基类默认的构造函数初始化派生类对象的基类部分,如果想拷贝或者移动基类部分,则必须在派生类的构造函数初始化列表中显示的调用基类的拷贝或移动构造函数
- 派生类析构函数进行对象销毁时只负责销毁由派生类自己分配的资源
- 对象销毁的顺序正好与其创建的顺序相反
- 如果构造函数或析构函数调用了某个虚函数,则我们应该执行与构造函数或析构函数所属类型相对应的虚函数版本
STL构成
-
容器:各种数据结构
-
算法
-
迭代器:扮演容器和算法之间的胶合剂 时所谓的“泛型指针”
-
仿函数:行为类似函数 可作为算法的某种策略 一般的函数指针可视为狭义的仿函数
-
配接器:一种用来修饰容器 仿函数 或迭代器接口的东西 比如容器配接器stack queue
-
配置器:负责空间配置与管理
组件交互关系:容器通过空间配置器获取数据存储的空间,算法通过迭代器存取容器的内容,仿函数可以协助算法完成不同的策略变换 配接器可以修饰或套接仿函数
迭代器
作用
STL的中心思想是:将容器和算法分开,彼此独立设计,最后再以胶着剂将它们撮合。容器和算法的泛型化不难,可以使用class templates和function templates,迭代器就是扮演粘胶角色
迭代器类别&萃取编程
- 迭代器所指对象的型别,称为该迭代器的value type(p85)
- 关键词typename的用意在于告诉编译器这是一个型别,如此才能通过编译
- 萃取各个迭代器的特性,这里所谓的迭代器特性,指的是迭代器的相应型别。当然,若要这个所谓的特性萃取机可以正常工作,每一个迭代器必须遵守约定,自行以内嵌型别定义的方式定义出相应的型别
- 需要萃取的原因:在算法之中运用迭代器,很可能会用到其相应的型别,迭代器所指之物的型别便是其中之一,假设算法之中有必要声明一个变量,故需要对型别进行萃取
- 偏特化可以实现无论面对的是迭代器 原生指针 都可以通过萃取获取正确的value type
例子:vector内部存储类型为int的元素,现在要对其进行排序,使用迭代器将其和排序算法进行粘合,传入迭代器vector::iterator,但是在算法内部需要使用容器内所存元素的类型去定义某些变量,如果未实现萃取的功能,则该算法无法进行。
萃取迭代器种类的原因p95 简要来讲就是为了提高效率的去决定使用哪一种算法
常用迭代器
- iterator_categoty 迭代器种类
- value_type 迭代器所指对象的型别
- difference_type 两个迭代器之间的距离
- pointer
- reference
迭代器种类
- input 只读
- ouput 只写
- forward 允许写入型算法在此种迭代器所形成的区间上进行读写操作
- bidirectional 可双向移动
- random access 前四种都只供应一部分指针算术能力 前三种支持operator++ 第四种加上operator-- 第五种则涵盖所有指针的算数能力
总结
- 设计相应的型别是迭代器的责任
- 设计适当的迭代器是容器的责任 唯有容器自己知道该设计什么样的迭代器来遍历自己,并执行迭代器该有各种行为
- trains编程技巧被大量运用 利用内嵌型别编程技巧与编译器的template参数推到功能