C++入门七式——模板初阶
目录
函数模板
函数模板概念
函数模板格式
函数模板的原理
函数模板的实例化
模板参数的匹配原则
类模板
类模板的定义格式
类模板的显式实例化
当面对下面的代码时,大家会不会有一种无力的感觉?明明这些代码差不多,只是因为类型不同,就要多写几行代码。如果有泛型编程该有多好!
void swap(int& left, int& right)
{int tmp = left;left = right;right = tmp;
}
void swap(double& left, double& right)
{double tmp = left;left = right;right = tmp;
}
void swap(char& left, char& right)
{char tmp = left;left = right;right = tmp;
}
虽然在这种情况下,函数重载也可以实现,但是有以下几个不好的地方:
- 重载的函数仅仅是类型不同,代码复用效率比较低,只有当新类型出现时,就需要用户自己增加对应的函数。
- 代码的可维护性比较低,一个出错所有重载均出错。
那是否能告诉编译器一个模子,让编译器根据不同的类型利用该模子生成代码呢?这就要讲到我们今天的内容了——模板。
函数模板
函数模板概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化根据实参类型产生函数的特定版本。
函数模板格式
#include<iostream>
using namespace std;
template <typename t>
//typename是用来定义模板参数关键字,也可以用class(不能用struct
void swap(t& x, t& y)
{t tmp = x;x = y;y = tmp;
}
int main()
{return 0;
}
函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器使用方式产生了特定具体类型函数的模具。所以模板其实就是将本来该由我们做的重复的事情交给了编译器。
编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数来调用 。
函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
1.隐式实例化:模板参数根据实参自动推演。
#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;//隐式实例化add(a1, a2);add(d1, d2);//在模板中,编译器一般不会进行类型转换操作,因为一旦转化出现问题,编译器就需要背黑锅//add(a1, d1);//有两种解决方法:1.用户自己来强制转化2.使用显式实例化add(a1,(int)d1);return 0;
}
2. 显式实例化:在函数名后的<>中指定模板参数的实际类型
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;//显式实例化add<int>(a1, a2);add<double>(d1, d2);add<int>(a1, d1);return 0;
}
模板参数的匹配原则
-
一个非模板函数和一个同名函数模板可以同时存在 ,而且该函数模板还可以被实例化为这个非模板函数(现成的非模板函数优先)。
#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{cout << "模板" << endl;return x + y;
}
int add(int x, int y)
{cout << "现成" << endl;return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;add(a1, a2);return 0;
}
- 对于非模板函数和一个同名函数,我们都可以调用,但会调用更匹配的。
#include<iostream>
using namespace std;
template<typename T1,typename T2>
T1 add(T1 x, T2 y)
{cout << "模板" << endl;return x + y;
}
int add(int x, int y)
{cout << "现成" << endl;return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;add(a1, d2);return 0;
}
可以看出编译器会优先调用更匹配的模板,即使它比较麻烦。
类模板
基本都是显式实例化,因为无法借助数来推是什么类型
类模板的定义格式
template<class T1, class T2>
class t//类模板名
{};
举例:
#include<iostream>
using namespace std;
template<class T>
class stack
{
public:stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};
template<class T>
void stack<T>::Push(const T& data)
{_array[_size] = data;++_size;
}
int main()
{stack<int>st1;return 0;
}
类模板的显式实例化
实例化模板需要在类模板后加<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
int main()
{stack<int>st1;return 0;
}