模版与群体数据的组织
函数模版与类模版
模板可以实现参数化多态性,就是将程序处理对象的类型参数化,使一段程序能够用于处理多种不同类型的对象。
函数模板
函数模板存在的意义简单来说就是为了避免两个只有处理数据类型不同的函数重复编写,使代码的可重用性大大提高,从而提高软件的开发效率。
语法形式在函数定义前加上语句template<模板参数表>
模板参数表的内容:
- 类型参数: class(或typename)标识符
- 常量参数: 类型说明符 标识符
- 模板参数: template<参数表> class 标识符
实例:
1 | //通用类型的绝对值函数 |
函数模版与函数有着本质的区别
- 函数模版本身在编译时不会生成任何目标代码,只有函数模版的实例会生成目标代码。
- 被多个源文件引用的函数模板,需要连通函数体一同放在头文件中,而不能像普通函数那样只把声明放在头文件中。
- 函数指针也只能指向函数模版的实例,不能指向函数模板。
类模版
使用类模板能够可以为类定义一种模式,使得类中的某些数据成员,某些成员函数的参数,返回值或局部变量能取任意类型。
类模版的声明方式与函数模版方式相同,
1 | //在类模版以外的地方定义成员函数 |
线性群体
线性群体顾名思义,元素的位置与其位置关系时互相对应的。分类可以分为,直接访问、顺序访问和索引访问。直接访问指不需要按照顺序直接跳到需要访问的位置,而顺序访问只能够按照元素排列顺序从头访问。
直接访问群体—数组类
要求自己设计一个可变长度的数组,点击查看源码,并列出一些语法注意点。
语法规定“=”,“[ ]”,“( )”,“->”只能被重载为成员函数,而且派生类中的“=”运算函数总会隐藏基类中的“=”运算符。
如果我们希望在程序中像使用普通数组一样使用Array类的对象,需要对其进行重载指针转换运算符。
指针转换运算符的作用
为了说明重载指针转换运算符的必要性,先来看看下面这段程序:
1 |
|
这里函数 read 的第一个形参是 int 指针,而数组名a 是一个int 型地址常量,类型恰好是匹配的。如果希望在程序中像使用普通数组一祥做用Array类的对象,将上述 main两数修改如下:
1 | int main () |
情况会怎样呢?这回在调用read 时会发现实参类型与形参类型不同,这时编译系统会试图进行自动类型转换:将对象名转换为 int * 类型。由于a是自定义的类型对象,所以编译系统提供的自动转换功能当然无法实现这一转换,因此我们需要自行编写重载的指针类型转换函数。
C++中,如果想将自定义类型T的对象隐含或显式地转换为S 类型,可以将operator S定义为T的成员函数。这样,在把T类型对象显式隐含转换为 S 类型,或用static_cast 显式转换为 S 类型时,该成员函数会被调用。转换操作符的重载函数不用指
定返回值的类型,这是由于这种情况下重载函数的返回类型与操作符名称一致,因此C++标准规定不能为这类函数指定返回值类型(也不要写 void)。
而当对象本身为常数时,为了避免通过指针对数组内容进行修改,只能将对象转换为常指针。
在这个Array类中重载指针转换运算符的写法如下;
1 | template<class T> |
顺序访问群体—链表类
1 | // LinkedList.h |
链表的基本操作:
- 生成链表
- 插入结点
- 查找结点
- 删除结点
- 遍历链表
- 清空链表
栈类
栈类模版的编写,点击查看源码。
栈的元素其实可以用数组表示也可以用链表表示。
栈的基本操作:
- 初始化
- 入栈
- 出栈
- 清空栈
- 访问栈顶元素
- 检测栈的状态(满、空)
队列类
设计的是循环队列,用的是数组,增减较为的麻烦,其实我觉得用链表实现的话不需要用循环。
群体数组的组织
简单的排序和查找都较为的基础,在此插入一些图片和链接以更好的理解。