模板的概念

在C++标准库中,几乎所有的代码都是模板代码。

模板是一种参数化的多态工具。

所谓参数化的多态性,是指将程序所处理 的对象的类型参数化,使一段程序代码可以用于处理多不同类型的对象。

采用模板编程,可以为各种逻辑功能相同而数据类型不同的程序提供一种代码共享的机制。

继承和组合提供了重用对象代码的方法,而模板提供了重用源代码的方法。


函数模板

所谓函数模板,实际上是建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板(Function Template)。

函数模板不是实际的函数,而是编译器用于生成一个或多个函数的 “模具”。在编写函数模板时,不必为形参、返回值或局部变量指定实际类型,而是使用类型形参来指定通用数据类型。当编译器遇到对函数的调用时,它将检查其实参的数据类型,并生成将与这些数据类型配合使用的函数代码。

一但定义了函数模板,就可以将类型参数用于函数定义和函数声明了。说得直白一点,原来使用 int、float、char 等内置类型的地方,都可以用类型参数来代替。

函数模板的定义

函数模板的一般说明形式如下:

template < 模板形参表>
返回值类型 函数名(模板函数形参表){//函数定义体
}

函数模板的定义以关键字template开头

template之后<>中是函数模板的参数列表

函数模板的参数是类型参数,其类型为classtypename

template<class T>
template<class T1, class T2>

模板的参数定义之后是函数模板的定义,是一个将类型参数作为某种类型使用的函数。

函数模板的参数名在模板中作为一种类型使用,可以用于函数的形参、函数返回值和函数的局部变量。

模板的每个形式参数要在函数的参数列表中至少出现一次。

形式参数名的作用域局限于函数模板的范围内。


函数模板的使用

函数模板规定了对数据的处理流程。

某些数据类型(模板的参数)要等到模板实例化时再确定具体的类型。

函数模板的实例化由编译器来完成
根据函数调用的实参类型确定模板形参的具体类型
用相应的类型替换函数模板中的模板参数完成函数模板的实例化


函数模板的示例

#include <iostream>
using namespace std;#define SIZE 8
template<class ElementType>
void sortArray
(ElementType b[], int len)
{for(int pass=0;pass<len-1;pass++)for(int i = pass+1; i < len;i++)if ( b[ pass ] > b[ i ] ){ElementType hold;hold = b[ pass ];b[ pass ] = b[ i ];b[ i ] = hold;}
}template<class ElementType >
void displayArray(ElementType b[],int len)
{for(int index=0;index<=len-1;index++)if ( index != len -1 )cout<<b[index]<<"\t";elsecout<<b[index]<<endl;
}
int main()
{int ai[SIZE] = {18,35,36,61,9,112,77,12};double af[SIZE]={12.1, -23.8, 3.7, -16.0,9.1, 12.12, 7.7, 56.3};cout << "Before sorting:\n"<< "ai: \t";displayArray(ai, SIZE);sortArray(ai, SIZE);cout << "After sorting:\n"<< "ai: \t";displayArray(ai, SIZE);cout <<"Before sorting:\n"<< "af: \t";displayArray(af, SIZE);sortArray(af, SIZE);cout <<"After sorting:\n"<< "af: \t";displayArray(af, SIZE);return 0;
}

执行结果:

Before sorting:
ai:     18      35      36      61      9       112     77      12
After sorting:
ai:     9       12      18      35      36      61      77      112
Before sorting:
af:     12.1    -23.8   3.7     -16     9.1     12.12   7.7     56.3
After sorting:
af:     -23.8   -16     3.7     7.7     9.1     12.1    12.12   56.3
#include <iostream>
using namespace std;
template<typename T>
void Swap(T &a, T &b){T temp = a;a = b;b = temp;
}
int main(){//交换 int 变量的值int a1 = 10, a2 = 20;Swap(a1, a2);cout<<"交换int变量的值:"<<a1<<", "<<a2<<endl;//交换 float 变量的值float b1 = 1.5, b2 = 2.5;Swap(b1, b2);cout<<"交换float变量的值:"<<b1<<", "<<b2<<endl;//交换 char 变量的值char c1 = 'A', c2 = 'B';Swap(c1, c2);cout<<"交换char变量的值:"<<c1<<", "<<c2<<endl;//交换 bool 变量的值bool d1 = false, d2 = true;Swap(d1, d2);cout<<"交换bool变量的值:"<<d1<<", "<<d2<<endl;return 0;
}

执行结果:

交换int变量的值:20, 10
交换float变量的值:2.5, 1.5
交换char变量的值:B, A
交换bool变量的值:1, 0

重载函数模板

C++语言允许一个函数模板可以使用多个模板参数或者重载一个函数模板。

用户可以用非模板函数重载一个同名的函数模板


类模板

类模板:将类定义中的数据类型参数化。

类模板实际上是函数模板的推广,可以用相同的类模板来组建任何类型的对象集合。

类模板的定义

template  <类型形参表>
class  <类名>
{     //类说明体  };template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数1>(形参表)
{     //成员函数定义体  };template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数2>(形参表)
{     //成员函数定义体  };
···
template  <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数n>(形参表)
{     //成员函数定义体  };

类模板的示例

#include <iostream>
using namespace std;template<class ElementType>
class Stack {public:Stack( int = 8 );   // 省缺栈元素的树数目为8~Stack(){ delete [] data; }int pop(ElementType &num);int push(ElementType num);
private:ElementType *data;      //栈数据存储int memNum;      //栈元素个数int size;      //栈大小
};template<class ElementType>
Stack<ElementType>::Stack(int s) {size = s > 0 ? s : 8;data = new ElementType[size];memNum = 0;
}template<class ElementType>
int Stack<ElementType>::pop
(ElementType &num) {if (memNum==0)return 0;num = data[ -- memNum ];return 1;
}template<class ElementType>
int Stack<ElementType>::push
(ElementType mem){if (memNum == size)return 0;data[ memNum ++ ] = mem;return 1;
}int main()
{Stack<double> doubleStack(6);double f = 3.14;cout<<"Pushing elements into doubleStack:\n";while (doubleStack.push(f)){cout << f << ' ';f += f;}cout << "\nStack is full. Cannot push " << f << " onto the doubleStack.";cout<<"\nPopping elements from doubleStack:\n";while (doubleStack.pop(f))cout<<f<<' ';
}

执行结果:

Pushing elements into doubleStack:
3.14 6.28 12.56 25.12 50.24 100.48
Stack is full. Cannot push 200.96 onto the doubleStack.
Popping elements from doubleStack:
100.48 50.24 25.12 12.56 6.28 3.14

派生类模板

通过继承可以产生派生类。

通过继承同样可产生派生的类模板。

几种不同的派生:①从一般类派生出类模板;②从类模板中派生出类模板

从一般类派生出类模版

一般类(其中不使用类型参数的类)作基类,派生出类模板(其中要使用类型参数)。

基本语法:

class CB
{   //CB 为一般类...
};
template <class T>
class CA:public CB { //被派生出的CA 为类模板,使用了类型参数TT t; //私有数据为T 类型的 public:...
};

从类模版派生出类模版

类模板作基类,派生出新的类模板。但仅基类中用到类型参数T(而派生的类模板中不使用T)。

基本语法:

template <class T>
class CB { //CB 为类模板T t; //私有数据为T 类型的
public:T gett(){ //用到类型参数T return t; } ...
}; template <class T>
class CA:public CB<T> {//CA 为类模板,其基类CB 为类模板
//将被“传递”给基类CB,本派生类中并不使用该类型参数T double t1; //私有数据成员 ...
};

类模板作基类,派生出新的类模板,且基类与派生类中均使用同一个类型参数T。

template <class T>
class CB { //CB 为类模板(其中使用了类型参数T),它将作为类模板CA 的基类T t; //数据成员为T 类型的 public:T gett(){ //用到类型参数Treturn t;} ... };
template <class T>
class CA:public CB<T> { //CA 为类模板,其基类CB 也为类模板。注意,类型参数T 将被“传递”给基类CB;本派生类中也将使用这同一个类型参数T T t1; //数据为T 类型的
public: ...};

类模板作基类,派生出新的类模板,但基类中使用类型参数T2,而派生类中使用另一个类型参数T1(而不使用T2)。

template <class T2> class CB { //CB 为类模板(其中使用了类型参数T2),它将作为类模板CA 的基类T2 t2; //数据为T2 类型的 public: ...
};
template <class T1, class T2>class CA:public CB<T2> { //CA 为类模板,其基类CB 也为类模板。注意,类型参数T2 将被“传递”给基类CB;本派生类中还将使用另一个类型参数T1 T1 t1; //数据为T1 类型的 public: ...
};

类模板继承示例

#include <iostream>
using namespace std;class CMyString:public basic_string<char>
{public:void Trim();void LTrim();void RTrim();CMyString();CMyString(const char *s);
};void CMyString::LTrim(){string::size_type len;if ((len=this->size())==0){return;}this->erase(0,this->find_first_not_of(" \t",0));
}void CMyString::RTrim(){string::size_type len;if ((len=size())==0){return;}this->erase(this->find_last_not_of(" \t")+1);
}CMyString::CMyString():basic_string<char>()
{}
CMyString::CMyString(const char *s):basic_string<char>(s)
{}
void CMyString::Trim(){LTrim();RTrim();
}
int main(){CMyString str1("\t   Hello World    ");str1.Trim();cout<<str1<<endl;return 0;
}

执行结果:

Hello World

派生类和模板

为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配子(adapter)来完成的。通用性是模板库的设计出发点之一,这是由泛型算法和函数对象等手段达到的。

派生类的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到繁,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。

模板追求的是运行效率,而派生追求的是编程的效率。

复习笔记(八)——C++模板相关推荐

  1. STM32复习笔记(十八) —— 高级定时器(输出比较)

    STM32复习笔记(十八) -- 高级定时器(输出比较) 1.配置步骤 1)选择计数器时钟 (内部,外部,预分频器) 2)将相应的数据写入TIMx_ARR and TIMx_CCRx寄存器中 3)可设 ...

  2. 《微型计算机原理与接口技术》期末总复习 —— 一篇匆匆忙忙的复习笔记

    这篇复习笔记是针对<微型计算机原理与接口技术>后面几章的 前面的汇编复习内容在 "零.学习笔记总目录" 的 "汇编考前复习" 中 ✅ 这篇笔记中可能 ...

  3. 【Web】javaEE课程复习笔记

    JavaEE复习笔记 根据上课的笔记整理与补充.涵盖web应用开发基础,jsp,标签,注解,struts,spring, mvc, 数据访问等内容 (因为转于个人blog,csdn图片无法显示,可至下 ...

  4. 【山东大学】web数据管理——复习笔记

    写在前面 若有图片加载失败,请科学上网 . 本文为对软件学院连老师的PPT课件总结所得的复习笔记,仅供参考.不保证对考点的全覆盖,以PPT为主. 对往年考过的题相关知识点前面都标注了"考过& ...

  5. 2018.8.14-C#复习笔记总

    2018.8.14-C#复习笔记总 using System; using System.Collections.Generic; //using System.Linq; using System. ...

  6. 2018.8.14-C++复习笔记总

    2018.8.14-C++复习笔记总 // CPPTEST.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iost ...

  7. c++语言自定义操作符,C++语言复习笔记二

    C++语言复习笔记二 零.OOP 特征:抽象-封装-继承-多态 一.自定义数据类型 1.类 class 类名 { private: 私有成员(本类) public: 公共成员(所有) protecte ...

  8. angular复习笔记4-模板

    Angular复习笔记4-模板 简介 模板是一种自定义的标准化页面,通过模板和模板中的数据结合,可以生成各种各样的网页.在Angular中,模板的默认语言是HTML,几乎所有的HTML语法在模板中都是 ...

  9. Halcon 学习笔记八:颜色识别

    Halcon 学习笔记八:颜色识别 一.图像处理需要的知识 二.图像处理的预处理和分割过程 二.颜色识别的方法 三.例子一 四.例子二 五.例子三 一.图像处理需要的知识 1.图像处理基础(rgb(h ...

  10. 【前端】HTML标签基础复习笔记

    不够完美又何妨?万物皆有裂隙,那是光进来的地方. 文章目录 HTML复习笔记 JavaWeb相关概述 HTML概述 HTML语法 基本标签 图片标签 链接 列表标签 块级标签 表格标签 表单标签 HT ...

最新文章

  1. Git 看这一篇就够了
  2. 【OpenCV3】图像旋转与平移——cv::warpAffine()详解
  3. JAVA--网络编程
  4. Serverless 时代前端避坑指南
  5. 关于zencart的magic zoom
  6. 前端Javascript与Nodejs的异同
  7. servlet中servletContext的五大作用(一)
  8. Servlet相关(servletconfig、servletcontext、request)
  9. 【Python 10】汇率兑换3.0(while循环)
  10. C++ string与vectorfloat类型相互转换之stringstream
  11. datatable 参数详细说明
  12. 关于ATmega328P和ATmega328PB中16位定时器的使用
  13. Windows安全中心打开空白
  14. Bicubic介绍及Python实现
  15. Ubuntu本地hosts泛解析
  16. 常见的服务器报错数字的意思
  17. 免费个人商城系统源码推荐
  18. 3D风车动画CSS HTML代码
  19. iOS 局域网通讯 MultipeerConnectivity
  20. 【技巧】windows剪切板

热门文章

  1. springboot controller调用service_绝了!Dataway让SpringBoot不在需要Controller、Service、DAO......
  2. pytorch 笔记 :实现Dropout
  3. pandas python csv_python:pandas合并csv文件的方法(图书数据集成)
  4. matlab绘制横向柱状图
  5. LeetCode-数学-9. 回文数
  6. Word 2016加载Endnote x9的方法
  7. 大数据分析之环境部署
  8. elasticSearch6源码分析(5)gateway模块
  9. 微服务实践分享(5)缓存中心
  10. 有哪些通俗易懂的例子可以解释 IaaS、PaaS、SaaS 的区别?