目录
1.泛型编程
如果在C++中,能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件 (即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
关于泛型的理解可以总结下面的一句话,它是把数据类型作为一种参数传递进来。
模板是泛型编程的基础,可分为
函数模板和类模板两大类。
2.函数模板
c语言实现交换函数
void swapi(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
void swapd(double* x, double* y)
{
double tmp = *x;
*x = *y;
*y = tmp;
}
void swapc(char* x, char* y)
{
char tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 10, b = 20;
double c = 0.1,d = 0.5;
char e = 'a', f = 'b';
swapi(&a, &b);
swapd(&c, &d);
swapc(&e, &f);
return 0;
}
太繁琐了,我们C++可以用模板
template <typename T>
void Swap(T& left, T& right)
{
T tmp = left;
left = right;
right = tmp;
}
int main()
{
int a = 10, b = 20;
double c = 0.1, d = 0.5;
char e = 'a', f = 'b';
Swap(a, b);
Swap(c, d);
Swap(e, f);
return 0;
}
函数模板格式: template <class / typename T>
这里关键字typename和class效果一样,后面名字用T或者Tp等等都可以。
我们再看下面一个例子
template <typename T>
T Add(const T& x, const T& y)
{
return x + y;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 0.1, b2 = 0.5;
cout << Add(a1, a2) << endl;
cout << Add(b1, b2) << endl;
//error
cout << Add(a1, b2) << endl;
cout << Add(b1, a2) << endl;
return 0;
}
下面为什么会出错呢,因为类型不同,编译器也不知道要那个类型
解决办法
1.用户自己强制类型转换
//强制类型转化
cout << Add(a1, (int)b2) << endl;
cout << Add(b1, (double)a2) << endl;
2、显示实例化
//显示实例化
cout << Add<int>(a1, b2) << endl;
cout << Add<double>(b1, a2) << endl;
3、通用加法函数模板
template <typename T1,typename T2>
T1 Add(const T1& x, const T2& y)
{
return x + y;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 0.1, b2 = 0.5;
cout << Add(a1, b2) << endl;
cout << Add(b1, a2) << endl;
return 0;
}
T1为模板,以a1,b1为模板,打印出来,a1为int,b1为double。
这个是T2为模板,b2,a2,打印出来
如果已经存在一个Add函数,那么编译器会调用该函数还是模板?
会直接调用函数,因为调用模板,模板还是会调用函数,多此一举。
3.类模板
C++中类模板的声明格式为template<模板形参表声明><类声明>,
并且类模板的成员函数都是模板函数
template <class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
以动态顺序表为例:
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public:
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
void PushBack(const T& data);
void PopBack();
// ...
size_t Size() { return _size; }
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
if (_pData)
delete[] _pData;
_size = _capacity = 0;
}
int main()
{
// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;
return 0;
}
Vector是类名,Vector<int>才是类型。
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
还要注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>:: 函数