模板主要应用于泛型编程,现在主要就是非常火的STL(标准模板库),对于公司项目来说利用模板的可能性不大,一般一个项目是无法达到模板这个要求的。
一、函数模板
函数模板的要求是:
1、函数名一致
2、参数个数一致
3、函数体一致
4、参数类型不同
函数模板的格式:
template<class/typename T1, class/typename T2, ...>
返回类型 函数名(参数列表){
函数体
}
举个例子:
template<typename T>
void Swap(T &a, T &b) {
T t = a;
a = b;
b = t;
}
int main() {
int a = 5;
int b = 3;
cout << "a = " << a << ", b = " << b << endl;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
double c = 5.6;
double d = 3.2;
cout << "c = " << c << ", d = " << d << endl;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
string e = "aaa";
string f = "bbb";
cout << "e = " << e << ", f = " << f << endl;
Swap(e, f);
cout << "e = " << e << ", f = " << f << endl;
system("pause");
return 0;
}
输出结果:
利用同一个函数模板可以应用于不同的类型,上面的每一次Swap的调用其实本质都是:
Swap(a, b); ------> Swap<int>(a, b);
Swap(c, d); ------> Swap<double>(c, d);
Swap(e, f); ------> Swap<string>(e, f);
这个过程就是从函数模板转换成模板函数的一个过程, 左边是一种函数模板的隐式实例化,右边是函数模板的显示实例化。
1、函数模板与普通函数重载
template<typename T>
T getmax(T a, T b) {
return a > b ? a : b;
}
int getmax(int a, int b) {
return a > b ? a : b;
}
int main(){
cout << getmax(8,5) << endl;
system("pause");
return 0;
}
对于这样的代码,编译器采用完全匹配的方式调用参数为int类型的函数
int getmax(int a, int b) {
return a > b ? a : b;
}
因为函数模板的编译需要进行两次编译:
第一次:不考虑类型编译;
第二次:匹配类型,生成可调用的二进制文件
在第一次编译的时候编译器就找到了完全匹配的函数,因为不会再进行第二次编译了。
所以当函数模板与普通函数重载时,优先调用完全匹配的普通函数。
2、函数模板与函数模板重载
template<typename T>
T* const& getmax(T* const& a, T* const& b) {
return *a > *b ? *a : *b;
}
template<typename T>
T const& getmax(T const& a, T const& b) {
return a > b ? a : b;
}
int main(){
cout << getmax(5,8) << endl;
system("pause");
return 0;
}
这段代码会调用下面这个模板函数,
template<typename T>
T const& getmax(T const& a, T const& b) {
return a > b ? a : b;
}
当模板函数与模板函数重载时,根据参数列表进行匹配。
二、结构体模板
template<typename T>
struct student
{
T num;
string name;
int age;
};
int main(){
student<int> stu1 = {1239234, "郭靖", 18};
cout << stu1.num << " " << stu1.name << " " << stu1.age << endl;
student<string> stu2 = {"xuesheng2", "黄蓉", 16};
cout << stu2.num << " " << stu2.name << " " << stu2.age << endl;
system("pause");
return 0;
}
输出结果:
三、类模板
STL中常用的就是类模板,比如vector,stack都是类模板,这里就拿stack为例:
类模板的格式:
template<typename T1, typename T2, ...>
class 类名{
类内部实现;
};
若成员函数在类内部定义则与普通类的成员函数的定义一样, 若成员函数在类外部定义则要这样写,以下面stack的构造函数为例,在函数前不仅要加
template<typename T>
域名要写成这种形式:
MyStack<T>::函数名
自实现的Stack类模板
template<typename T>
MyStack<T>::MyStack(int s) {
size = s;
arr = new T[size];
top = 0;
}
#include<iostream>
#include<string>
using namespace std;
template<typename T>
class MyStack {
public:
MyStack(int s = 1024);
~MyStack();
bool isEmpty();
bool isFull();
void push(T num);
T pop();
private:
T *arr;
int top;
int size;
};
template<typename T>
MyStack<T>::MyStack(int s) {
size = s;
arr = new T[size];
top = 0;
}
template<typename T>
MyStack<T>::~MyStack() {
delete[]arr;
}
template<typename T>
bool MyStack<T>::isEmpty() {
return top == 0;
}
template<typename T>
bool MyStack<T>::isFull() {
return top == size;
}
template<typename T>
void MyStack<T>::push(T num) {
arr[top++] = num;
}
template<typename T>
T MyStack<T>::pop() {
return arr[--top];
}
int main() {
MyStack<int> ms;
ms.push(20);
cout << ms.pop() << endl;
ms.push(30);
cout << ms.pop() << endl;
ms.push(10);
cout << ms.pop() << endl;
cout << "-------------------" << endl;
MyStack<string> mstr;
mstr.push("aaa");
cout << mstr.pop() << endl;
mstr.push("bbb");
cout << mstr.pop() << endl;
mstr.push("ccc");
cout << mstr.pop() << endl;
cout << "-------------------" << endl;
MyStack<double> msdou;
msdou.push(1.1);
cout << msdou.pop() << endl;
msdou.push(2.2);
cout << msdou.pop() << endl;
msdou.push(3.3);
cout << msdou.pop() << endl;
system("pause");
return 0;
}
输出结果:
MyStack<int> ms
对于这句代码,是个从类模板转换成模板类,再生成对象的过程。
如果写类模板,最好是先用一种简单的类型写一遍,再把类型替换掉就可以了。
再粘一个自实现的vector的例子,个人认为还是蛮典型的:
#include<iostream>
using namespace std;
template<typename T>
class MyVector {
public:
MyVector(int s = 1024) {
arr = new T[s];
size = 0;
}
MyVector(MyVector<T> &another) {
int len = another.getSize();
arr = new T[len];
for (int i = 0; i < len; i++) {
arr[i] = another.arr[i];
size++;
}
}
MyVector<T>& operator=(MyVector<T> & another) {
if (this == &another)
return *this;
delete[]arr;
int len = another.getSize();
arr = new T[len];
for (int i = 0; i < len; i++) {
arr[i] = another.arr[i];
size++;
}
return *this;
}
T& operator[](int i) {
if (i > size){
cerr << i << "不存在" << endl;
}
return arr[i];
}
~MyVector() {
delete []arr;
}
int getSize() {
return size;
}
void push_back(T num) {
arr[size++] = num;
}
T pop_back() {
return arr[--size];
}
friend ostream& operator<<(ostream& os, const MyVector& mv) {
for (int i = 0; i < mv.size; i++)
os << mv.arr[i] << " ";
return os;
}
private:
T *arr;
int size;
};
int main() {
MyVector<int> mv;
for(int i = 0; i < 10; i++)
mv.push_back(i);
cout << mv << endl;
cout << "------------------------" << endl;
MyVector<double> v2;
for (int i = 0; i < 10; i++)
v2.push_back(i + 0.1);
cout << v2 << endl;
cout << "------------------------" << endl;
MyVector<char> v3;
char c = 'a';
for(int i = 0; i < 10; i++){
v3.push_back(c++);
}
cout << v3 << endl;
cout << "------------------------" << endl;
system("pause");
return 0;
}
输出结果:
四、模板特化
template<typename T1, typename T2>
class Temp {
public:
void func(T1 t1, T2 t2) {
cout << "class Temp " << endl;
}
};
//完全特化
template<> //这里不能漏掉
class Temp<int, double> {
public:
void func(int t1, double t2) {
cout << "class Temp<int, double>" << endl;
}
};
//局部特化
template<typename T>
class Temp<T, double>{
public:
void func(T t1, double t2) {
cout << "class Temp<T, double>" << endl;
}
};
template<typename T>
class Temp<T, T> {
public:
void func(T t1, T t2) {
cout << "class Temp<T, T>" << endl;
}
};
int main(){
Temp<int, int> temp1;
temp1.func(1, 2);
Temp<int, double> temp2;
temp2.func(1, 2.0);
Temp<float, double> temp3;
temp3.func(1.3, 2.5);
Temp<char, string> temp4;
temp4.func('a', "sfafsa");
system("pause");
return 0;
}
输出结果:
五、模板默认参数
1、类模板默认参数
template<typename T1 = int, typename T2 = double>
class test {
public:
void func() {
cout << typeid(t1).name() << " " << typeid(t2).name() << endl;
}
private:
T1 t1;
T2 t2;
};
int main(){
test<> test1; //虽然使用了默认参数,但是<>不能少
test1.func();
test<float> test2;
test2.func();
test<char, int> test3;
test3.func();
system("pause");
return 0;
}
输出结果:
2、函数模板默认参数
template<typename T = int>
void foo(T t) {
cout << typeid(t).name() << endl;
}
int main(){
foo("strsqa");
foo((float)12);
system("pause");
return 0;
}
输出结果:
3、类模板中的成员函数模板
template<typename T1 = int, typename T2 = double>
class test {
public:
template<typename T = int>
void func(T t) {
cout << typeid(t1).name() << " " << typeid(t2).name() << " " << typeid(t).name() << endl;
}
private:
T1 t1;
T2 t2;
};
int main(){
test<> test1;
test1.func(1);
test<float> test2;
test2.func((float)1);
test<char, int> test3;
test3.func((double)1);
system("pause");
return 0;
}
输出结果:
总结:
1、模板不是一个完整的类型,使用到类型时要用到尖括号<>。
2、结构体模板和类模板必须使用显示实例化,也就是必须加<>,函数模板可以隐式实例化。