泛型编程
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。
模版是泛型编程的基础
模版
模版分为函数模版和类模版
函数模版
template:模版
函数模版的格式
template < class T1,class T2,class T3,…,class Tn>
返回值类型 函数名(参数列表) {}
定义模版参数的关键字可以用class,也可以用template
//template <typename T>
template <class T>
void swap(T& a,T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int i = 1,j = 2;
double m = 1.1,n = 2.2;
swap(i,j);
swap(m,n);
//用的是同一个模版,但是编译器生成的是不同的函数
return 0;
}
用模版的好处:C语言规定函数不能同名,要写两个不同名的函数,C++有函数重载,可以同名,但是也要写两个参数不同的函数,用函数模版可以提高效率不用写两个函数了
1.函数模版的三种写法:
template <class T1,class T2>
template <class T1,typename T2>//关键字混用也可以
template <typename T1,typename T2>
2.一个模版参数只能接收相同的类型
template <class T>
//只能传相同的类型,只能接收一种类型
template <class T1,class T2>
//可以接收不同的类型,可以传相同,也可以传不同类型
3.推导实例化和显示实例化
模版实例化:用函数模版生成对应的函数,跟用类名生成对应的对象一样(用类名实例化对象)
- 推导实例化
1.推导实例化
template <class T>
void swap(T& a,T& b)
{
T tmp = a;
a = b;
b = tmp;
}
int main()
{
int i = 1,j = 2;
double m = 1.1,n = 2.2;
swap(i,j);//推导i和j是int类型
swap(m,n);//推导m和n是double类型
return 0;
}
2.强制类型转换可以解决类型不明确的问题
int a1 = 0;
double d1 = 0;
cout << Add(a1,(int)d1) << endl;
cout << Add((double)a1,d1) << endl;
3.显示实例化
cout << Add<int>(a1,d1) << endl;
cout << Add<double>(a1,d1) << endl;
有时只能用显示实例化,不能用推导实例化
template <class T>
T* func1(int n)
{
return new T[n];
}
//不在参数位置写T,不能推导出T类型
int main()
{
func1(10); (x)
double* p1 = func1<double>(10); (v)
return 0;
}
如果有实际的函数存在和模版同时也存在,就走函数,因为编译器追求高效,不用推导实例化
类模版
类模版的定义格式
template <class T1,class T2,class T3...,class Tn>
class
{
//类内成员定义
};
在类内声明,在类外初始化,要单独声明模版参数
template<class T>
class Stack
{
void Push(const T& x);//声明
};
//初始化
template<class T>
void Stack<T>::Push(const T& x)
{
if (_size == _capacity)
{
T* tmp = new T[_capacity * 2];
memcpy(tmp, _array, sizeof(T) * _size);
delete[] _array;
_array = tmp;
_capacity *= 2;
}
_array[_size++] = x;
}
模版使用和定义不分离在两个文件中(.h和.cpp),会造成链接错误
不看模版类型是否匹配,要看实例化后的函数类型是否匹配
C++中没有realloc,只能这样扩容
void Push(const T& x)
{
if(_size == _capacity)
{
T* tmp = new T[_capacity*2];//扩2倍
memcpy(tmp,_array,sizeof(T)*_size);
//把数据拷贝到tmp中
delete[] _array;
//销毁原空间
_array = tmp;//给新空间地址
_capacity *= 2;//空间扩2倍
}
_array[_size++] = x;
//插入数据x
}
类模版都是显示实例化
不同的类型
Stack<int> st1;//int
Stack<double> st2;//double
用的同一个模版,调用不同的类,编译器生成了两个不同的类,类模版的参数类型不同(int,double)