6.1 模板的概念

C++允许用同一个函数定义函数,这些函数的参数个数和参数类型不同。例如求最大值的max函数,
int max(int x,int y)
{
       return (x>y)?x:y;
}
long max(long x,long y)
{
      return (x>y)?x:y;
}
double max(double x,double y)
{
      return (x>y)?x:y;
}
发现:
虽然函数体是一样的,但是它们所处理的参数类型和返回值类型都不一样,所以是完全不同的函数。都是为了求和,如果每一次都重复写这些函数,比较麻烦。那么,是否可以写一次这样的求和代码就能完成各自的需求呢?

C++提供的模板就解决了这个问题。模板极大提高了代码的复用性。
它可以实现类型参数化,即把类型定义为参数。

模版分为函数模板和类模板,它们分别允许用户构造模版函数和模板类。

6.2 函数模板和模板函数

所谓函数模板,实际上就是建立一个通用函数,其函数返回类型和形参类型是不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。在调用函数时系统会根据实参的类型(模板实参)来取代模板中虚拟类型从而实现了不同的函数功能。

函数模板的声明格式如下:
template<typename 类型参数>
返回类型 函数名 (模板形参表)
{
函数体;
}

也可以定义如下格式:
template<class 类型参数>
返回类型 函数名 (模板形参表)
{
函数体;
}

(1)template:是一个声明模板的关键字,它表明声明一个模板
(2)类型参数:通常用C++标识符表示,如T、Type等,实际上是一个虚拟的类型名,现在未指定它是哪一种具体的类型,但使用函数模板时,必须将类型参数实例化。

(3)typename和class的作用相同,都是表示其后面的参数是一个虚拟的类名(即类型参数).

例如,将求最大值函数max定义成员模板,
template<typename T> //T为类型参数
T max(T x,T y) //"T x,T y"表示模板形参表
{
     return (x>y)?x:y;
}

或者
template<class T> //T为类型参数
T max(T x,T y) //"T x,T y"表示模板形参表
{
     return (x>y)?x:y;
}

注意:在使用函数模板时,关键字typename(或class)后面的类型参数,必须实例化,即
用实际的数据类型(既可以是系统定义的标准数据类型),也可以是用户自定义的类
型替代它。将函数模板中的类型参数实例化的参数称为模板参数。

//例6.1 函数模板的使用

#include<iostream.h>
template <typename T> //声明模板,其中T为类型参数
T max(T x,T y) //定义函数模板,"T x,T y"为模板形参表
{
return (x>y)?x : y;
}
int main()
{
int i1=,i2=,i3;
double d1=50.344,d2=4656.346,d3;
char c1='k',c2='n',c3;
i3=max(i1,i2); //调用函数模板,i1和i2为模板实参,此时AT被int取代 d3=max(d1,d2); //调用函数模板,此时AT被double取代 c3=max(c1,c2); //调用函数模板,此时AT被char取代 cout<<"i_max="<<i3<<endl;
cout<<"d_max="<<d3<<endl;
cout<<"c_max="<<c3<<endl;
return ;
}
/*
程序运行结果是:
i_max=56
d_max=4656.35
c_max=n 说明:函数模板实现了函数参数的通用性,作为一种代码的重用机制,可以大幅度地提高程序
设计的效率。 函数模板max(AT,AT)
实例化 实例化 实例化
max(int,int) max(double,double) max(char,char)
*/

//例6.2  函数模板的使用举例

#include<iostream.h>
template <typename T> //模板声明,其中T为类型参数
T max(T* array,int size=)
{
T total=;
for(int i=;i<size;i++)
//total+=*(array++);
total+=array[i];
return total;
};
int int_array[]={,,,,,,,,,};
double double_array[]={1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.10};
int main()
{
int itotal=max(int_array,); //调用函数模板,此时T被int取代
double dtotal=max(double_array,); //调用函数模板,此时T被double取代
cout<<"这个整型数组的元素之和是:"<<itotal<<endl;
cout<<"这个双精度数组的元素之和是:"<<dtotal<<endl;
return ;
}
程序运行结果是:
这个整型数组的元素之和是:55
这个双精度数组的元素之和是:59.6 在该程序中,生成两个模板函数。其中,"sum(int_array,10)"将类型参数T实例化为int型,因为int_array为一个整型数组名,是一个指向int类型的指针;第二个也是如此...
(1)在函数模板中允许使用多个类型参数。但是应当注意template定义部分的每一个类型
参数前必须有关键字typename或name,例如,下面这个程序中建立了有两个类型参数的函数
模板。

//例6.3 有两个类型参数的函数模板举例

#include<iostream.h>
template<class T1,class T2> //模板声明,其中T1、T2是类型参数
void myfunc(T1 x,T2 y) //有两个类型参数的函数模板
{
cout<<x<<" "<<y<<endl;
}
int main()
{
myfunc(,"hao");
myfunc(0.123,10L);
return ;
}
程序运行结果:
10 hao
0.123 10 在此程序中,函数模板实例化后生成了两个模板函数,其中"mayfunc(10,"hao")分别用模板实参int和char*将类型参数T1和T2进行实例化。其中"mayfunc(0.123,10L)分别用模板实参float和long将类型参数T1和T2进行实例化。 (2)在template语句与函数模板定义语句之间不允许有别的语句,例如下面的程序段就不能
编译。
template <typename T>
T max(T x,T y)
{
return (x>y)?x:y;
} (3)模板函数类似于重载函数,只不过它更严格一些而已。函数被重载的时候,在每个函数体内可以执行不同的操作,但同一函数模板实例化后的所有模板函数都必须执行相同的操作。
例如,下面的重载函数就不能用模板函数代替,因为它们所执行的操作是不同的。
函数1:
void outdate(int i)
{
cout<<i<<endl;
}
//因为两个函数的输出结果不一样,不可以用函数模板
函数2:
void outdate(double d)
{
cout<<"d="<<d<<endl;
} (4)同一般函数一样,函数模板也可以重载。

//例6.4  函数模板的重载举例

//例6.4  函数模板的重载举例
#include<iostream.h>
template <typename T> //模板声明,其中T为类型参数
T max(T x,T y) //定义有两个类型参数的函数模板max
{
return (x>y)?x:y;
}
template <typename T> //定义有三个类型参数的函数模板max
T max(T x,T y,T z)
{
T temp;
temp=(x>y)?x:y;
return (temp>z)?temp:z;
}
int main()
{
int i=,j=;
int i1=,j1=,k1=;
double a=10.1,b=20.1;
double a1=10.1,b1=20.1,c1=30.1;
cout<<"max"<<"("<<i<<","<<j<<")"<<"="<<max(i,j)<<endl;
cout<<"max"<<"("<<i1<<","<<j1<<","<<k1<<")"<<"="<<max(i1,j1,k1)<<endl;
cout<<"max"<<"("<<a<<","<<b<<")"<<"="<<max(a,b)<<endl;
cout<<"max"<<"("<<a<<","<<b<<","<<c1<<")"<<"="<<max(a1,b1,c1)<<endl;
return ;
}

程序运行结果是:
max(10,20)=20
max(10,20,30)=30
max(10.1,20.1)=20.1
max(10.1,20.1,30.1)=30.1

(5)函数模板与同名的非模板函数可以重载。在这种情况下,调用的顺序是:首先寻找一个参数完全匹配的非模板函数,如果找到了就调用它;若没有找到,则寻找函数模板,将其实例化,产生一个匹配的模板函数,若招到了,就调用它。恰当运用这种机制,可以很好的处理一般与特殊的关系。

例6.5 应用举例:

#include<iostream.h>
template <class T> //声明模板,其中T为类型参数
T max(T t1,T t2) //定义函数模板,max(T t1,T t2)为模板形参表
{
cout<<"调用模板函数.\n";
return (t1>t2)?t1:t2;
}
int max(int x,int y)
{
cout<<"调用非模板函数.\n";
return (x>y)?x:y;
}
int main()
{
int a=,b=;
double x=50.34,y=4656.34;
char c1='k',c2='n';
cout<<"max"<<"("<<a<<","<<b<<")"<<"="<<max(a,b)<<endl; //找到匹配的int型max函数,调用非模板函数
cout<<"max"<<"("<<x<<","<<y<<")"<<"="<<max(x,y)<<endl; //未找到匹配的int型max函数,调用模板函数
cout<<"max"<<"("<<c1<<","<<c2<<")"<<"="<<max(c1,c2)<<endl;//未找到匹配的int型max函数,调用模板函数
return ;
}

程序运行结果是:
调用非模板函数.
max(10,56)=56
调用模板函数.
max(50.34,4656.34)=4656.34
调用模板函数.
max(k,n)=n

C++:函数模板与模板函数的更多相关文章

  1. 3.2 STL中的函数对象类模板

    *: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...

  2. [c++][语言语法]函数模板和模板函数 及参数类型的运行时判断

    参考:http://blog.csdn.net/beyondhaven/article/details/4204345 参考:http://blog.csdn.net/joeblackzqq/arti ...

  3. c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别

    一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...

  4. C++ template学习一(函数模板和模板函数)

    函数模板和模板函数(1)函数模板函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计.它的最大特点是把函数使用的数据类型作为参数.函数模板的声明形式为:templat ...

  5. ThinkPHP第五天(提交类型判定常量IS_POST等,错误页面种类,Model实例化方式,模板中使用函数,foreach循环,模板中.语法配置)

    1.IS_GET.IS_POST.IS_PUT.IS_DELETE.IS_AJAX常量,方便快捷实现各个判断. 在Action类中还可以使用$this->isPost()等进行判断. 2.错误页 ...

  6. C++ - 模板类模板成员函数(member function template)隐式处理(implicit)变化

    模板类模板成员函数(member function template)隐式处理(implicit)变化 本文地址: http://blog.csdn.net/caroline_wendy/articl ...

  7. C++模板学习:函数模板、结构体模板、类模板

    C++模板:函数.结构体.类 模板实现 1.前言:(知道有模板这回事的童鞋请忽视) 普通函数.函数重载.模板函数 认识. //学过c的童鞋们一定都写过函数sum吧,当时是这样写的: int sum(i ...

  8. [C++基础]那些容易被混淆的概念:函数/数组指针-指针函数/数组,类/函数模板-模板类/函数

    函数指针-指针函数 函数指针的重点是指针.表示的是一个指针,它指向的是一个函数.eg: int (*pf)(); 指针函数的重点是函数.表示的是一个函数,它的返回值是指针.eg: int* fun() ...

  9. C++ 函数模板一(函数模板定义)

    //函数模板定义--数据类型做参数 #include<iostream> using namespace std; /* 函数模板声明 1.函数模板定义由模板说明和函数定义组成,并且一个模 ...

随机推荐

  1. 使用wget备份禅道

    禅道7.1,管理了公司所有项目.需要每月备份. 主机安装在一台windows上.为了方便,写个脚本自动调用禅道的备份功能,并把服务器上的备份文件下载到本地. @echo off setlocal re ...

  2. Mysql ubuntu下的安装卸载

    删除 mysql sudo apt-get autoremove --purge mysql-server-5.0sudo apt-get remove mysql-serversudo apt-ge ...

  3. ASP.NET MVC 学习第二天

    今天使用mvc完成简单的增删改,内容比较简单,来熟悉一下mvc,数据库操作是用前面的ef,也算是温习一下ef吧. 新建mvc项目,在项目中的Models内添加ef,我这里只操作一下简单的user表.里 ...

  4. Using self-defined Parcelable objects during an Android AIDL RPC / IPC call

    Using self-defined Parcelable objects during an Android AIDL RPC / IPC call In my previous post “Usi ...

  5. 历时一周,unity3d+xtion打造我的第一个休闲体感小游戏《空降奇兵》

    1.游戏介绍 本游戏属于休闲小游戏,主要操作如下: 菜单控制:举起左手或右手,点击左边或者右边的菜单:挥动左手或右手,选择关卡: 操作方式:玩家跳跃,游戏中的伞兵从飞机开始降落:玩家通过控制伞兵的左右 ...

  6. 小杜同学关于Query的一点知识

    小杜同学关于jQuery的一点知识 1.关于jQuery jQuery就是一个JavaScript的函数库.既然是JS的的函数库,它自然是做JS做的东西了.毕竟jQuery只是用JavaScript编 ...

  7. Careercup - Facebook面试题 - 6204973461274624

    2014-05-02 02:28 题目链接 原题: I/P: N, k O/P: all subset of N with exactly K elements. eg: I/p: N = , K = ...

  8. Getting Started with Java

    “学前”说明:<Learn Java for Android>这本书内容很多,都是精华,建议大家看英文版的.在这里我不打算一一总结书中的内容,书中每章节后面的exercises都很好,非常 ...

  9. trie树(前缀树)

    问题描述:   Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...

  10. 用hibernate自动创建mysql表,添加失败org.hibernate.exception.SQLGrammarException

    今天遇到了一个很坑人的问题,从昨晚一直搞到今天早上,终于发现了,先整理下: [背景]:利用hibernate自动给mysql创建一个表,然后为表里面添加一行记录,非常的简单(当然其中还涉及到sprin ...