C++:函数模板与模板函数

简介:

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=10,i2=56,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 0;
} 
/*
程序运行结果是:
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=0)
{
 T total=0;
 for(int i=0;i<size;i++)
  //total+=*(array++);
  total+=array[i];
 return total; 
};
int int_array[]={1,2,3,4,5,6,7,8,9,10};
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,10);          //调用函数模板,此时T被int取代
 double dtotal=max(double_array,10);    //调用函数模板,此时T被double取代
 cout<<"这个整型数组的元素之和是:"<<itotal<<endl;
 cout<<"这个双精度数组的元素之和是:"<<dtotal<<endl;
 return 0; 
}
复制代码
程序运行结果是:
这个整型数组的元素之和是: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(10,"hao"); 
 myfunc(0.123,10L);
 return 0;
}
复制代码
程序运行结果:
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=10,j=20;
 int i1=10,j1=20,k1=30;
 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 0;
} 
复制代码

程序运行结果是:
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=10,b=56;
 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 0;
}
复制代码

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

 

程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!
本文转自当天真遇到现实博客园博客,原文链接:http://www.cnblogs.com/XYQ-208910/p/4912720.html ,如需转载请自行联系原作者
相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
121 10
|
1月前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
49 4
|
1月前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
36 3
|
1月前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
32 0
|
2月前
|
程序员 C++ 容器
在 C++中,realloc 函数返回 NULL 时,需要手动释放原来的内存吗?
在 C++ 中,当 realloc 函数返回 NULL 时,表示内存重新分配失败,但原内存块仍然有效,因此需要手动释放原来的内存,以避免内存泄漏。
|
2月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
20 1
|
2月前
|
存储 前端开发 C++
C++ 多线程之带返回值的线程处理函数
这篇文章介绍了在C++中使用`async`函数、`packaged_task`和`promise`三种方法来创建带返回值的线程处理函数。
83 6
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
50 9
|
2月前
|
C++
C++ 多线程之线程管理函数
这篇文章介绍了C++中多线程编程的几个关键函数,包括获取线程ID的`get_id()`,延时函数`sleep_for()`,线程让步函数`yield()`,以及阻塞线程直到指定时间的`sleep_until()`。
45 0
|
2月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
39 3