第七章 类模板与向量
类模板工作原理

类模板工作原理
类模板(class template)是C++中的一种特殊类型,用于实现
通用的数据结构或算法。
类模板工作的原理可以简要描述如下:
1. 定义模板:使用关键字`template`开头,后面跟着模板参数
列表和类定义。
模板参数列表可以包含类型参数、非类型参数和模板模板参数。
2. 实例化模板:当使用模板创建对象时,编译器会根据实际的类型参数替换模板中的类型参数,生成具体的类定义。
这个过程称为模板的实例化。
3. 生成类定义:实例化模板后,编译器会基于模板定义生成特定类型的类定义。
这个类定义会包含模板定义中的成员函数和成员变量,但类型参数会被实际的类型替代。
4. 编译生成的代码:编译器根据生成的类定义,将代码编译成可执行的机器码。
生成的代码中的类型相关操作会被转换为实际类型的操作。
5. 运行程序:编译生成的代码会被加载到内存中,并被计算机执行。
在运行时,类模板的对象会根据实际的类型参数进行操作,而非模板定义时的类型参数。
需要注意的是,类模板的实际代码是在编译器进行模板实例化时生成的,而不是在运行时动态生成的。
这意味着每种实际类
型的类定义是独立的,不同实例的对象可以在相同的程序中同时存在,并且彼此之间是完全隔离的。
第7章 模板(gai)

5
7.1.3 模板的概念
模板的类属参数由调用它的实际参数的具体数 据类型替换, 据类型替换,由编译器生成一段真正可以运行的代 这个过程称为实例化。 码。这个过程称为实例化。
模板 (函数模板或类模板)
实例化
实例化
实例化 模板函数 模板类 对 象
6
7.2 函数模板
7.2.1 函数模板的定义 7.2.2 函数模板的实例化 7.2.3 函数模板的重载
10
7.2.1 函数模板的定义
【例7.1】定义函数模板求两个数中的较大值。 】定义函数模板求两个数中的较大值。 template <typename T> T max(T a, T b) {return a>b? a:b;} 当程序中使用这个函数模板时, 当程序中使用这个函数模板时,编译程序将根据函数调 用时的实际数据类型产生相应的函数。 用时的实际数据类型产生相应的函数。如产生求两个整 数中的较大值的函数, 数中的较大值的函数,或求两个浮点数中的较大值函数 等等。 等等。
11
7.2.2 函数模板的实例化
函数模板是对一组函数的描述, 函数模板是对一组函数的描述,它以类型作 为参数及函数返回值类型。 为参数及函数返回值类型。 当编译系统在程序中发现有与函数模板中相匹 配的函数调用时,便生成一个重载函数。 配的函数调用时,便生成一个重载函数。该重载 函数的函数体与函数模板的函数体相同, 函数的函数体与函数模板的函数体相同,参数为 具体的数据类型。 具体的数据类型。 我们称该重载函数为模板函数, 我们称该重载函数为模板函数,它是函数模板 的一个具体实例。 的一个具体实例。
这些栈除了数据类型之外,操作完全相同, 这些栈除了数据类型之外,操作完全相同,就可 用类模板实现。 用类模板实现。
第 7 章 模板

可以看出,这些 函数版本的功能都是 相同的,只是参数类 型和函数返回类型不 同。 那么能否为这些 函数只写出一套代码 呢?
C++解决这个问题的一个方法 就是使用模板。
1. 模板的概念
在C++中,模板是实现代码重用机制的一种工 具,它可以实现类型参数化,即把类型定义为参数, 从而实现代码的可重用性。 C++程序由类和函数组成,C++中的模板也分 为类模板和函数模板。
与函数模板共ቤተ መጻሕፍቲ ባይዱ函数体;
重新定义函数体。
与函数模板共享函数体
void f(int i,char c) { int x; 通过借用函数模板的函数体来定义重载函数模 x=max(i,i); 板的非模板函数。 x=max(c,c); [例]: x= max(i,c);//调用int template <class T> max(int,int); T max(T a,T b) x=max(c,i); //调用 { T c; int max(int,int); if (a>b) c=a; } else c=b; 因为普通函数具有隐式 return c; 类型转换能力,所以不出错! } int max(int, int); //与函数模板共享函数体
1) 定义类的一般形式:
template<class T1, class T2,……> //模板声明 class Name { … //类的定义 };
[例1]:向量类模板定义。
template<class T> class Vector
{
T *data;
int size; public: Vector(int i) { data=new T[i]; } ~Vector() { delete[] data; } T &operator[](int i) { return data[i]; }
类模板

for(i=0;i<5;i++) { cout<<"Push elements "<<i<<" in stack:"; cin>>temp; dblStack.Push(temp); //入栈 } while(!dblStack.Empty()) { temp=dblStack.Pop(); //出栈 cout<<"---> "<<temp<<endl; } return 0; Push elements 0 in stack:11.11 } Push elements 1 in stack:22.22 Push elements 2 in stack:33.33 Push elements 3 in stack:44.44 Push elements 4 in stack:55.55 程序运行结果: ---> 55.55 ---> 44.44 ---> 33.33 ---> 22.22 ---> 11.11
【 10.3.2 标准模板类库简介】
1994年7月,STL正式成为标准C++库的一部分。 STL中的容器类是基于模板的,它既包含线性容器,也包含非线性容器, 其中主要有: vector(向量模板) list(链表模板) stack(栈模板) queue(队列模板) deque(双端队列模板) set(集合模板) map(映射模板) STL的迭代子可以看成是指针的推广,迭代子也可以是普通的指针。 顺序访问: 顺序迭代子使用++、--等进行移动,但只能顺序访 问容器中的对象。
{ T maxitem; maxitem=item1>item2 ? item1: item2; maxitem=maxitem>item3? maxitem: item3; return maxitem; } #endif
第7章 类模板与向量

则这个实例是与前者毫无关系的对象,虽然它们都产生于同一个模板,但分别属于不同的模板类。
【】求4个数中最大值的类模板程序。
#include <iostream>
using namespace std;
template<class T>
可以用一个非模板类为一组模板提供一种共同实现的方法。注意比较下面两个例子的各自特点。
【例7.4】设计一个非模板类Point类,然后设计一个继承Point类的类模板Line。
#include <iostream>
using namespace std;
class Point{
int x,y;
【例7.1】使用类模板的实例
template <class T>
class TAnyTemp{
带参数T的模板声明,可用typename代替class
T x,y;
public:
TAnyTemp(T X,T Y):x(X),y(Y){} //构造函数
T getx(){ return x; }//内联成员函数,返回类型为T
{
Point a(3,8); //对象a是整数坐标
a.display();
Line<int>ab(); //线段ab的两个坐标均是整数
ab.display();
Line<double>ad(4,5,6.5,7.8);
//线段ad的一个坐标是整数,另一个是实数
ad.display()
}
C++程序设计--标准模板库STL介绍及应用(第7章)

拷贝构造函数 将容器初始化为现有同类容器副本的构造函数
析构函数 不再需要容器时进行内存整理的析构函数
empty() 容器中没有元素时返回true,否则返回false
max_size() 返回容器中最大元素个数
size() 返回容器中当前元素个数
operator= 将一个容器赋给另一个容器
备注
2020/8/4
STL对C++的影响
在STL之前,C++支持三种基本的编程样式—面向过程 编程、数据抽象和面向对象编程。
在STL出现之后,C++可以支持一种新的编程模式—泛 型程序设计。
STL并不完美,但是,它开辟了程序设计的新天地,它 拥有的影响力甚至于超过了巨大的C++群体。
2020/8/4
8
C/C++程序设计教程--面向对象分册
有两个版本返回reverse_iterator或 const_reverse
_ iterator,引用容器第一个元素前面一位
erase(p, q) erase(p)
从容器中清除一个或几个元素
clear() 清除容器中所有元素
2020/8/4
备注 不适用于 容器适配器
不适用于 容器适配器
不适用于 容器适配器
描述
后进先出的值的排列。
先进先出的值的排列。 元素的次序是由作用于所存储的值对 上的某种谓词决定的一种队列。 由{键,值}对组成的集合,以某种作 用于键对上的谓词排列。 允许键对有相等的次序的映射。
类型 头文件
容器适 配器
<stack>
容器适 <queue
配器
>
第一章C++语言编程入门
第一章C++语言编程入门★ 课程概述第1章C++语言编程入门第2章函数第3章类与对象第4章指针与引用第5章继承第6章运算符重载第7章多态与虚函数第8章群体类第9章模板第10章I/O流第11章标准模板类库STL 第12章异常处理总复习3.1 类与对象概念的引入 2.1 函数的定义及调用 1.1 C++语言的产生 4.1 指针 5.1 继承与派生7.1 运算符重载的语法 6.1 C++语言是一种面向对象的程序11.1 多态性概述 3.2 基本数据结构知识 2.1.1 函数的定义1.2 类的声明 4.1.1 数据存储 3.3 对象的声明 2.1.2 指针的声明及使用 5.2 单继承10.1 I/O流概述设计语言函数的声明各章节总结12.1一元运算符异常处理的基本语法 4.1.2 6.2 线性群体9.1 构造函数与析构函数8.1 函数模板11.2 C++程序的开发步骤标准模板类库STL简介 3.4 2.1.3 函数的调用 1.3 4.1.3 指针运算 5.2.1 公有派生 3.5 类的组合 2.1.4 函数调用的执行过程 1.4 一个简单C++程序的组成7.2 虚函数6.3 二元运算符的重载4.1.4 与对象有关的指针8.1.1 可直接访问的线性群体―― 11.3 C++语言的词法记号 5.2.2 私有派生 3.6 向量 2.2 静态成员10.2 输入输出格式控制1.5 函数调用时参数的传递4.1.5 void和const指针2.3 内联函数3.6.1 静态数据成 1.6 数据类型 6.4 特殊的运算符数组类异常处理的使用9.2 类模板 5.2.3 保护派生12.2 4.2 动态内存分配11.4 运算符与表达式链表类的使用 2.4 指针与数组 3.6.2 静态成员函数 1.7 带默认形参值的函数 4.3 多继承 5.3 抽象类7.3 作用域6.4.1 =运算符的重载 3.7 指针与函数 2.5 友元8.1.2 顺序访问群体――链表类10.3 文件输入输出1.7.1 运算符 4.4 11.5 常对象、常成员函数与常数据成双端队列 3.8 派生类的构造函数与析构函数2.5.1 作用域分类5.4 字符串1.7.2 表达式4.5 6.4.2 ++和--运算符的重载员4.6 引用2.5.2 局部变量与全局变量1.7.3 表达式中数据类型的转换12.3 标准C++库中的异常类 5.5 二义性问题11.6 控制语句 3.9 引用与函数 2.6 类的作用域及对象的生存期10.4 栈与队列用户自定义类型的输入输出 1.8 递归调用 4.7 综合实例7.4 群体数据的排序与查找6.4.3 new 8.2 虚基类和delete运算符的重载 5.6 重载函数 2.7 指针与引用 3.9.1 类作用域 1.8.1 选择语句4.8 11.7 C++语言的系统函数集合2.8 赋值兼容原则3.9.2 对象生存期1.8.2 循环语句5.7 程序实例――链表 6.4.4 []的重载4.9 3.10 面向对象标记1.8.3 转移语句进程第1章C++语言编程入门1.1 C++语言的产生1.6 数据类型1.2 C++语言是一种面向对象的1.6.1 基本数据类型程序设计语言 1.6.2 变量 1.2.1 C++语言和面向对象的 1.6.3 常量程序设计 1.6.4 自定义数据类型1.2.2 C++语言与C语言的关1.7 运算符与表达式系1.7.1 运算符 1.3 C++程序的开发步骤 1.7.2 表达式 1.4 一个简单C++程序的组成1.7.3 表达式中数据类型的转换 1.5 C++语言的词法记号 1.8 控制语句 1.5.1 字符集 1.8.1 选择语句 1.5.2 词法记号1.8.2 循环语句1.8.3 转移语句C++语言是一种已得到广泛使用的面向对象的程序设计语言。
类模板的定义和使用
类模板的定义和使用类模板的定义和使用如同函数模板一样,使用类模板使用户可以为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数、某些成员函数的返回值能取任意类型。
类模板是对一批仅仅成员数据类型不同的类的抽象,程序员只要为这一批类所组成的整个类家族创建一个类模板,给出一套程序代码,就可以用来生成多种具体的类,(这类可以看作是类模板的实例),从而大大提高编程的效率。
定义类模板的一般形式是:template <类型名参数名1,类型名参数名2,…>class 类名{类声明体};例如,template <class T>class Smemory{…public:void mput(T x);…}表示定义一个名为Smemory的类模板,其中带类型参数T。
在类模板的外部定义类成员函数的一般形式是:template <类型名参数名1,类型名参数名2,…>函数返回值类型类名<参数名 1 参数名 2,…>::成员函数名(形参表){函数体}例如:template <class T>void Smemory<T>::mput(T x){…}表示定义一个类模板Smemory的成员函数,函数名为mput,形参x的类型是T,函数无返回值。
类模板是一个类家族的抽象,它只是对类的描述,编译程序不为类模板(包括成员函数定义)创建程序代码,但是通过对类模板的实例化可以生成一个具体的类以及该具体类的对象。
与函数模板不同的是:函数模板的实例化是由编译程序在处理函数调用时自动完成的,而类模板的实例化必须由程序员在程序中显式地指定,其实例化的一般形式是:类名 <数据类型 1(或数据),数据类型 2(或数据)…> 对象名例如,Smemory<int> mol;表示将类模板Smemory的类型参数T全部替换成int 型,从而创建一个具体的类,并生成该具体类的一个对象mol。
C++第7章 模板与群体类
C++语言程序设计
西南林学院 鲁莹
直 接 访 问 的 线 性 群 体
数组类模板的构造函数
// 构造函数 template <class T> Array<T>::Array(int sz) { if (sz <= 0) //sz为数组大小(元素个数),若小于 ,则输出错误信息 为数组大小( ),若小于 为数组大小 元素个数),若小于0, Error(invalidArraySize); size = sz; // 将元素个数赋值给变量 将元素个数赋值给变量size alist = new T[size]; //动态分配 动态分配size个T类型的元素空间 动态分配 个 类型的元素空间 if (alist == NULL) //如果分配内存不成功,输出错误信息 如果分配内存不成功, 如果分配内存不成功 Error(memoryAllocationError); }
C++语言程序设计
第九章 群体类 和群体数据的组织
西南林学院 鲁莹
C++语言程序设计
西南林学院 鲁莹
本章主要内容
模板 群体类 群体数据的组织
2
C++语言程序设计
西南林学院 鲁莹
第一部分—模板 第一部分 模板
函数模板 类模板
3
C++语言程序设计
西南林学院 鲁莹
函 数 模 板
函数模板
函数模板可以用来创建一个通用功能 的函数,以支持多种不同形参, 的函数,以支持多种不同形参,进一 步简化重载函数的函数体设计. 步简化重载函数的函数体设计. 声明方法: 声明方法:
16
#ifndef ARRAY_CLASS 动态数组类模板程序 #define ARRAY_CLASS using namespace std; #include <iostream> #include <cstdlib> #ifndef NULL const int NULL = 0; #endif // NULL enum ErrorType { invalidArraySize, memoryAllocationError, indexOutOfRange }; char *errorMsg[] = { "Invalid array size", "Memory allocation error", "Invalid index: " };
c++中vector向量几种情况的总结(向量指针,指针的向量)
c++中vector向量⼏种情况的总结(向量指针,指针的向量)1.标准库vector类型vector 是同⼀种类型的对象的集合,每个对象都有⼀个对应的整数索引值。
标准库将负责管理与存储元素相关的内存。
我们把 vector 称为容器,是因为它可以包含其他对象⽤ vector之前,必须包含相应的头⽂件。
#include <vector>1using std::vector;vector 是⼀个类模板(class template)。
使⽤模板可以编写⼀个类定义或函数定义,⽽⽤于多个不同的数据类型。
因此,我们可以定义保存 string 对象的 vector,或保存vector<int> ivec; // ivec holdsobjects of type intvector<Sales_item> Sales_vec; //holds Sales_items12注意:和其他变量定义⼀样(作为定义变量看待,如 int a;float b;),定义 vector 对象要指定类型和⼀个变量的列表。
上⾯的第⼀个定义,类型是vector(相当于int,或dou 定义⽅法为:vector<类型> 名称vector<类型> :作为⼀个整体,是类型,相当于int,float。
名称相当于变量的名字,a,b。
则以下⼏种都是成⽴的vector<int> k;//向量vector<int*>kk;//int指针的向量,以后再详细斟酌vector<int>*kkk;//vector向量指针vector<int*>*kkkk;//int指针的向量指针(对⽐int*p理解,指针变量前⾯的“*”表⽰该变量的类型为指针变量,p是指针变量名,⽽不是*p)vector 不是⼀种数据类型,⽽只是⼀个类模板,可⽤来定义任意多种数据类型。
vector 类型的每⼀种都指定了其保存元素的类型。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第七章 类模板与向量
本章主要内容
• •
类模板 向量与泛型算法
类模板
类与函数一样,当多个类之间只是数据类型不一样时, 类与函数一样,当多个类之间只是数据类型不一样时,也可以通过模板的形式定义成 一个特定的模板类 模板类。 一个特定的模板类。 该类为需要不同的数据类型的类提供了统一的模板, 类模板。 该类为需要不同的数据类型的类提供了统一的模板,即类模板。 类模板声明格式如下: 类模板声明格式如下: 声明格式如下 template <类模板参数>class 类名{……….} •模板参数可用作数据成员的类型、成员函数的参数类型、成员函数的返回值类型 等 template <class T> class Test{ T x, y; public: Test(T a,T b) { x=a; y=b; } T getx(){return x;} T gety(){return y;} };
5
向量的基本操作方法
访问向量容量信息的方法 访问向量容量信息的方法 向量容量 1.size()返回当前向量中对象的个数 a.size(); 2.max_size()返回向量最多可以容纳多少个对象,取决于硬件结构 a.max_size(); 3.capacity()返回无需再次分配内存就能容纳的对象个数,初始值为最初申请的元素个数, 当原来的空间存放满了之后,则在原来的基础上自动翻倍扩充 a.capacity(); 以上三者的关系如下: 以上三者的关系如下: max_size() >= capacity() >= size() 4.empty()返回当前向量是否为空,若为空返回true值,即返回值为1,反之为0 a.empty(); 访问向量中对象的方法 访问向量中对象的方法 向量中对象 1.front()返回向量中的第一个对象 a.front(); 2.back()返回向量中的最后一个对象 a.back(); 3.operator[ ](size_type n)返回向量中下标为n的向量元素 a.operator[ ](5); 参照P156【例7.9】 参照 【 】
3
向量与泛型算法
向量:数组的大小是不能改变的, 向量:数组的大小是不能改变的,而向量中存储的元素多少可以在运行时根据需要动 态的增长或缩小, 态的增长或缩小,向量是类模板 向量类模板定义在头文件vector中,提供了4种构造函数 中 提供了 种构造函数 向量类模板定义在头文件 1.vector<type> name; 定义空的向量表 vector<char> A; 2. vector<type> name(length); 定义具有length个type的向量 初始化为0 定义具有 个 的向量,初始化为 的向量 初始化为 vector<int> B(20); 3. vector<type> name(length,a); 定义具有 定义具有length个type的向量 初始化为 的向量,初始化为 个 的向量 初始化为a vector<int> C(20,1); 4. vector<type> name1(name); 使用已定义的向量 使用已定义的向量name构造新的向量 构造新的向量name1 构造新的向量 vector<int> D(C);
2
类模板
类模板的对象 创建对象时,显示的指定其数据类型,编译器就用指定的数据类型替代模板参数产生相 应的模板类 格式如下: 格式如下 类名<模板实例化参数类型>对象名(构造函数实参列表); Test<int> test1(15,30); 在类体外面定义成员函数时, 在类体外面定义成员函数时,必须重写类模板声明 template <模板参数 模板参数> 模板参数 返回类型 类名<模板类型参数 成员函数名 参数列表 类名 模板类型参数>::成员函数名 参数列表){……..} 模板类型参数 成员函数名(参数列表 参照P148【例7.2】 【 参照 】 类模板也可以像普通类一样继承,继承的方法也一样。 类模板也可以像普通类一样继承,继承的方法也一样。 继承的基类与派生类既可以是模板类,也可以是普通类。 继承的基类与派生类既可以是模板类,也可以是普通类。 基类与派生类既可以是模板类 模板类继承普通类 参照P149【例7.4】 参照 【 】 模板类继承模板类 参照P150【例7.5】 参照 【 】
7
6
向量的基本操作方法
在向量中插入对象的方法 向量中插入对象的方法 1.push_back(const T&) 在向量尾部插入一个对象 a.push_back(‘w’); 2.insert(iterator it,const T&)在it所指向的位置前插入一个对象 a.insert(3,’h’); 3.insert(iterator it,size_type n,const T&X)在it所指向的位置前插入n个值为X的对象 a.insert(3,5,’h’); 在向量中删除对象的方法 向量中删除对象的方法 1.pop_back()删除向量中最后一个对象 a.pop_back(); 2.erase(iterator it)删除it所指向位置的对象 a.erase(3); 3.clear()删除向量中的所有对象,此时empty()返回true值 a.clear(); 参照P157【例7.10】 【 参照 】
4Байду номын сангаас
向量与泛型算法
向量的第一个元素从0开始 向量的第一个元素从 开始 允许同类型的向量之间相互赋值, 允许同类型的向量之间相互赋值,跟他们的长度无关 不能直接使用列表初始化向量,可先定义一个数组, 不能直接使用列表初始化向量,可先定义一个数组,再把数组的内容复制给向量 int a[3]={1,2,3}; vector<int>b(a,a+3);
向量的数据类型可以是基本数据类型,也可以是构造类型, 向量的数据类型可以是基本数据类型,也可以是构造类型,但必须符合构成规则 参考P154【例7.7】~【例7.8】 参考 【 】 【 】 向量具有指向第一个元素的标记begin()和指向结束的标记 和指向结束的标记end() 向量具有指向第一个元素的标记 和指向结束的标记 定义泛型指针 vector<type> ::iterator 泛型指针名 泛型指针名; 定义逆向泛型指针 reverse_vector<type> ::reverse_iterator 指针名; 指针名 参考P153【例7.6】 【 参考 】