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>,功能是可以排序任何类型的数组,当初自己在实现库函数的时候,曾经实现过这个函数,还做了一张图,如下:
由于没什么经验当初做这张图的时候,还是费了些功夫。关于这个函数的实现,可以在电脑里查一下专家的实现方法,这里我就不多介绍了,毕竟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""进行引用
这里只介绍了关于模板的一些基本用法,其他需要注意的,将在下篇统一整理
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。