C++ 当中的模板,通常作为处理由于参数类型不同,而引入的代码冗余情况。

    首先,我们讨论的是函数模板。

要讨论这个问题,我们先讨论如果实现一个通用的加法函数,该怎样去做?

    方法一 :使用C++当中的函数重载

int ADD(const int num1, const int num2)
{
 return (num1+num2);
}
double ADD(const double num1, const double num2)
{
 return (num1 + num2);
}
int main()
{
 cout << ADD(1,2) << endl;
 cout << ADD(1.2,3.4) << endl;
 system("pause");
 return 0;
}

    关于这种方法,虽然可以实现功能,但不得不说,属于最老实的做法,代码的复用率完全没有体现,而且,在只有返回值类型不相同的情况下,重载是不能够解决这类问题。代码维护起来,也是相当麻烦。

    方法二:利用C++当中的继承实现

    采用公共基类的方法解决这个问题,要求每实现一个类,都要特定继承某一个类,代码维护起来更加繁琐

    方法三:宏定义define 解决

    宏定义在定义时是不需要考虑类型的,表面上看起来可以实现这一功能,这一点完全继承自C语言。代码如下

#define ADD(a,b) ((a)+(b))

int main()

{

 cout << ADD(1, 2) << endl;

 cout << ADD(1.2, 3.4) << endl;

 system("pause");

 return 0;

}

    方便的同时,引入了另一个问题。宏定义是在预处理过程中就完成的,是不对传入期中的参数进行合法性检查的,一定程度上,我们可以说,这种方法是不安全的。

 

    讨论了这么多,突然想起了在C语言中有这么一个函数<qsort>,功能是可以排序任何类型的数组,当初自己在实现库函数的时候,曾经实现过这个函数,还做了一张图,如下:

wKiom1cQq9ThtK8YAAFOTZassEM959.png

由于没什么经验当初做这张图的时候,还是费了些功夫。关于这个函数的实现,可以在电脑里查一下专家的实现方法,这里我就不多介绍了,毕竟C++当中有着更加方便的工具---------->模板。

在这里先引入一个概念,范性编程,即编写与类型无关的逻辑代码,是代码复用的一种手段

    现在进入正题。认识模板之前,首先要提几个关键字:

      Point1:                                              template         typename       class

    其中typename与class的使用,在这里是完全相同的,而且class在模板当中也并不是定义类的。注意,在这里,不可以用struct代替class,同样,我们更加推荐用typename

现在来看具体的使用方法。首先定义一个函数模板。

template <class T>
T ADD(T a, T b)
{
 return (a + b);
}
int main()
{
 cout << ADD(1, 2) << endl;
 cout << ADD(1.2, 3.4) << endl;
 system("pause");
 return 0;
}

    T在这里是我们定义的一种类型。通过函数模板定义出来的函数,我们把它叫做模板函数,在编译过程中,如果我们只定义了函数模板,而没有定义模板函数,计算机是不会产生多余的代码数据,或者说,计算机不知道要产生什么样类型的代码数据。

Point2:

    同时,我们也可以在使用函数模板定义模板函数时通过"<typename>"指定参数类型,比如

 cout << ADD<int>(1, 2) << endl;

    值得注意的是,如果不指定参数类型,系统将根据你传入的变量,选择默认的参数类型。但是,如果没有参数,或者传入的参数并不是一个类型的话<参照next point>,需要自己声明,编译器无法自动给出。

Point3:

    除了参数类型可以作为模板参数外,变量也可作为模板参数,实现代码如下:

template <int size>
void display()
{
 for (int i = 0; i < size; i++)
 {
  cout << i << endl;
 }
}
int main()
{
 display<10>();
 system("pause");
 return 0;
}

千万不要忘记在使用时,对变量进行声明。定义模板时,此时参数前不需要加class或者typename,而需要加上该变量的类型。

Point4:

    模板支持多参数模板,定义函数模板时,每个类型参数前的typename或者class,以及变量的类型均不可省略。可以自己编码尝试。

Point5:

    函数模板与重载。

template <typename T>

void display(T a)

{

 cout << a << endl;

}

template <typename T>

void display(T a,T b)

{

 cout << a << endl;

}

template <typename T,int size>//每个函数模板之前都需要添加template语句

void display(T a)

{

 cout << a << endl;

}

    在我们定义函数模板的时候,各函数模板之间并不构成重载,因为此时,并没有在内存中产生代码量,而是在我们使用这些函数模板定义函数的时候,定义产生的函数彼此之间构成重载。

 

除了函数之外,类也有着模板------->类模板

    为什么要有类模板呢?和函数模板一样,同样是为了处理相同代码类型不同的情况。类模板代码如下:

template <class T>
class Data
{
public:
 Data(T d) :_data(d)
 {
 }
 void display()
 {
  cout << _data << endl;
 }
protected:
 T _data;
};
int main()
{
 Data<int> d(2);
 d.display();
 system("pause");
 return 0;
}

关于类外定义成员函数的方法:

template <class T>

class Data

{

public:

 Data(T d) :_data(d)

 {

 }

 void display();

protected:

 T _data;

};

void Data<int>::display()

{

 cout << _data << endl;

}

当然,我现在用的是单文件的定义,如果要在多文件环境下进行定义成员函数,需要在每个函数之前都加上"template<>",注意 ,是每个!!!

定义函数时,除了注意这个之外,还有需要注意的是要加上"<typename>",不管是定义模板函数还是实例化对象!否则编译失败。

当然,类模板也支持多参数,定义函数及实例化对象是,所有参数类型都需要注明。

注:受IDE环境与相关标准的限制,vs2005,vs2008,vs2010编译器下,模板代码不能分离编译,即模板的.h文件与.cpp文件不能分开进行编译,换句话说,就是无法写成.h文件与.cpp文件声明和定义分开这种情况。必须将所有代码都写入.h文件,通过include""进行引用

这里只介绍了关于模板的一些基本用法,其他需要注意的,将在下篇统一整理