函数和类模板及泛型编程

模板是C++泛型编程的基础,一个模板就是创建类或者函数的蓝图或者说公式。一个类模板或函数模板可以给程序省去多余的代码,以实现代码的复用。

一. 函数模板

假如我们想写一个比较大小的函数,我们先完成一个整型的比较,又想完成浮点数等的比较,可能很多人会想到用函数重载。这是可行的,但是在重载函数的过程中,实现的代码是一致的,就是函数的参数列表不同而已,这样写出来的代码重复太多,代码的复用率低。

我们可以利用函数模板解决这个问题:例如compare 的模板函数

 

template <class T>

int compare(const T& v1,const T& v2)
{
     if ( v1<v2) 
        return -1;
     if (v1>v2)
        return 1;
    return 0;
}

模板定义以关键字template开始,后跟一个模板参数列表(template parameter list):

template <class T> //class 可以替换为typename,两者无区别
<span style="color:#4f4f4f">模板参数表示在类或函数定义中用到的类型或值。当使用模板时,我们指定模板实参,将其绑定到模板参数上。</span>

实例化函数模板

当我们调用一个函数模板时,编译器用函数实参为我们推断模板实参,即我们调用compare 时,编译器使用实参的类型来确定绑定到模板参数 T 的类型。

例如:在下面的调用中:

cout << compare(1,0)<<endl;//T为int

模板类型参数和非模板类型参数

我们可以将模板类型参数看做类型说明符,比如 内置类型的int 或者类类型等。我们可以将T看作一种类型,它可以作为函数的返回值,也可以作为函数的参数类型。

template <class T>

除了定义模板参数,我们也可以定义非类型参数(nontype parameter)。一个非类型参数表示一个值而非类型。

template <int N,int M>
int compare ( const char (&p1) [N] ,const char (&p2) [M])
{ 
return strcmp(p1,p2);
}

在上面的函数中,当在模板中定义非类型参数时,在程序运行时,编译器会推断出参数的值,,并用值来代替参数,这些值必须是常量表达式。

我们将自己的参数定义为数组的引用,并且利用非模板参数定义了数组的大小,这样也可以验证N和M是否是常量表达式。

我们如下调用函数时,编译器会实例化如下版本

compare (“hi”,“mom")

 

int compare ( const char (&p1) [2] ,const char (&p2) [3])

inline 和 constexpr的函数模板

函数模板可以声明为inline 或constexpr的,和非模板函数一样,inline 或者 constexpr 说明符放在模板参数列表之后,函数返回类型之前,类型如下:

template <typename T> inline  T min(const T&v1,const T&v2); 

二. 类模板

类似函数模板,类模板以关键字template开始,后跟模板参数列表。类型如下:

template <class T> 
class 类名{  };

实例化类模板

在程序运行时,编译器会根据类的实例化来推断类模板的T类型。

Blob<string> names;
Blob<double> prices;

names的定义创建了一个Blob类,每个T类型都可被string替换;prices的定义创建了一个Blob类,每个T类型都可以被double类型替换。

类模板和友元

当一个类包含一个友元函数声明时,类与友元各自是否是模板相互是无关的。如果一个类模板包含一个非模板友元,则友元被授权可以访问所有模板实例;如果友元自身是模板,类可以授权所有模板实例,也可以只授权特定实例。

类模板的static成员

与任何其他类相同,类模板可以声明static成员。

template <typename  T> class Foo{
static std::size_t count()
{  return ctr;}
private:
static std:: size_t ctr;

}

对于上面这段代码,给定任意的类型T,都会有一个Foo<T> :: ctr 和Foo <T> :: count 成员,所有的Foo<T>类型的对象共享相同的ctr 和 count 函数。

与非模板类的静态成员函数或者变量相同,模板类的static 成员必须有且仅有一个定义,但是,每个类模板实例都有一个独立的static 变量或函数。

在类外定义并初始化static成员变量:

template <class T>
size_t Foo<T>:: ctr = 0;

与非类模板的静态成员相同,我们可以通过类类型对象来访问一个类模板的static成员,也可以使用域运算符直接访问成员:

Foo<int> f;
f.count();
Foo<int> :: count();

最后再看一个小知识:

如果我们希望使用一个模板类型参数的类型成员,就必须告诉编译器该名字是一个类型,我们需要使用typename关键字:

template <class T>
typename T:: value_type top(const T& v){ }

简而言之:如果想要在template中涉及一个嵌套从属类型名时,需用关键字 typename 告诉编译器该名字表示一个类型。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值