一、模板的认识
首先我们需要知道我们使用模板就是为了实现泛型编程。
你告诉编译器一个模子,让编译器根据不同的类型生成不同的代码,我们通过一个例子来说明。
template<typename Type>
void Swap(Type& a, Type& b)
{
cout << typeid(Type).name() << endl;
Type tmp = a;
a = b;
b = tmp;
}
void main()
{
int a = 10;
int b = 20;
Swap(a, b);
double d1 = 1.2;
double d2 = 2.3;
Swap(d1, d2);
char c1 = 'a';
char c2 = 'd';
Swap(c1, c2);
}
在这个例子中我们写了一个交换函数,交换两个类型相同的变量,如果在实际情况中我们需要实现不同类型的变量的交换,我们需要将代码写好多份,但是引入模板后,我们只需要将你需要每次改变的类型改为一个通用的可以变化的类型
template<typename +新定义类型名>
这样子从程序内部并不会提高效率,反而可能会降低效率,但是这方便了程序员的工作,避免代码的重复性。
二、函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据是参类型产生函数的特定类型版本。
格式:
template<tyoename T1,typename T2,…>
template<typename T>
void Swap(T& left,T& right>
{
T temp=left;
left=right;
right=temp;
}
这样写就会比上一份代码更加简略明了。
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
函数模板的实例化:
template<typename Type>
//函数模板
Type Sum(Type a, Type b)
{
cout << typeid(Type).name() << endl;
return a + b;
}
//模板函数
/*
int Sum(int a,int b)
{
return a+b;
}
*/
template<typename Type1, typename Type2>
Type1 Sum(Type1 a, Type2 b)
{
return a + b;
}
void main()
{
//自动推演(将参数传给形参列表自动推演出数据类型)
cout << Sum(1, 2) << endl;
cout << Sum('A', 'B') << endl;
cout << Sum(1.2, 2.4) << endl;
//编译错误-->参数1得到Type为整型,2.3Type又为double,出现二义性,Type只能代表一种类型
//cout << Sum(1, 2.3) << endl;
//保证Type有唯一的一种类型
cout << Sum(1, (int)2.4) << endl;
cout << Sum((double)1, 1.45) << endl;
cout << Sum<int>(1, 1.5) << endl;//将Type类型明确定义为整型
}
三、类模板
template<typename Type>
class SeqList
{
public:
SeqList(size_t sz)
{
capacity = sz;
base = new Type[capacity];
size = 0;
}
~SeqList()
{
delete[]base;
base = nullptr;
size = capacity = 0;
}
void pushBack(Type x);
void show()const;
public:
void pushBack(Type x)
{
base[size++] = x;
}
void show()const
{
for (int i = 0; i < size; ++i)
cout << base[i] << " ";
cout << endl;
}
private:
Type* base;
size_t capacity;
size_t size;
};
//类模板中的函数放在类外定义时,需要加模板参数列表
template<typename Type>
void SeqList<Type>::pushBack(Type x)
{
base[size++] = x;
}
template<typename Type>
void SeqList<Type>::show()const
{
for (int i = 0; i < size; ++i)
cout << base[i] << " ";
cout << endl;
}
void main()
{
//类模板实例化必须是显示的
//类模板不是真正的类,实例化后生成的具体数据类型的类才是真正的类
SeqList<int> list(10);
for (int i = 1; i <= 10; i++)
{
list.pushBack(i);
}
list.show();
SeqList<char>list1(10);
for (int i = 0; i < 10; i++)
{
list1.pushBack('a' + i);
}
list1.show();
}
类模板中的思路和函数模板是一样的,将那些需要很多份代码改变的参数我们就用模板参数来声明,这样就减少了很多程序员的工作。
模板代码不支持分离编译
注意:模板代码在写的时候不能声明和定义分开在两个文件中,否则会出现链接错误。