一.泛型编程
泛型编程即编写一种与
类型无关的逻辑代码,是一种复用.
二.模板
模板分为
模板函数和
模板类.
- 模板函数
我们经常使用的swap函数,用来交换两个同类型的参数
Swap(int* a,int*b); //用来交换两个整形
Swap(char* a,char* b); //用来交换两个字符
Swap(float* a,float* b); //用来交换两个浮点型
...
这样看下去,如果我们有n中类型需要交换,我们就需要写n个Swap函数
C++就是考虑到这一点,采用了模板,实现一堆逻辑相同,只有参数不相同的代码,极大的复用了代码,使本该由程序员自己编写的代码,模板在底层为我们实现
模板函数格式
template <class 形参名1,class 形参名2,class 形参名3...>
返回类型 函数名(参数列表)
{
//TODO
}
上面的 class 可是用 typename 替换
下面我们看一下Swap模板函数的实现
#include <iostream>
using namespace std;
#include <stdio.h>
template<class T>
void Swap(T& a,T& b)
{
T c = a;
a = b;
b = c;
}
int main()
{
int a = 1, b = 2;
printf("before a = %d,b = %d\n",a,b);
Swap(a,b);
printf("after a = %d,b = %d\n",a,b);
char ch1 = 'a',ch2 = 'b';
printf("before ch1 = %c,ch2 = %c\n",ch1,ch2);
Swap(ch1,ch2);
printf("after ch1 = %c,ch2 = %c\n",ch1,ch2);
float f1 = 3.14, f2 = 6.28;
printf("before f1 = %f,f2 = %f\n",f1,f2);
Swap(f1,f2);
printf("after f1 = %f,f2 = %f\n",f1,f2);
return 0;
}
运行结果:
汇编底层实现
我们可以看到,交换三种类型的参数,Swap在汇编层分别调用了三个函数,这就证明编译器在底层为我们实现了三个参数不同的函数,用来做交换
其实,编译器会处理代码,在发现调用模板参数时,为我们自动生成一份对应参数的函数代码,这几个函数构成了
重载.
注意:
在不调用模板参数时,编译器并不会形成代码,只会检查模板的框架符不符合语言要求,一旦被调用才回去实例化出代码.
我把main函数中调所有调用模板的函数屏蔽掉,编译代码,显示成功,可见这里并没有实例化出代码,编译器自然检测不到这里的错误
但是一旦我们调用,结果就不一样了
- 模板类
以普通顺序表举例:
以前我们定义顺序表的时候都会这样定义:
typedef
int
DataType; //指定出顺序表中的类型,这里为int
class
Vector
{
public
:
Vector();
~Vector();
Vector(
const
Vector& v);
Vector&
operator
=(Vector v);
size_t Size()
const
;
size_t Capacity()
const
;
void
Expand(size_t n);
void
PushBack(DataType value); //使用类型的时候用 typedef出来的DataType
void
PopBack();
void
Insert(size_t pos, DataType value);
void
Erase(size_t pos);
void
Show();
protected
:
DataType* _first;
DataType* _finish;
DataType* _endofstorage;
};
以上的定义方法使得我们的顺序表中只可以存储int类型的变量
下面我们用模板来定义顺序表
定义格式
template <class 形参1,class 形参2,...>
类名
{
//TODO
};
这里的class也可以用typename替换
template
<
class
T> //指定顺序表中的类型,这里为泛型T
class
Vector
{
public
:
Vector();
~Vector();
Vector(
const
Vector<T>& v);
Vector<T>&
operator
= (Vector<T> v);
void
Expand(size_t n);
void
PushBack(T value); //使用类型的时候直接使用 T
void
PopBack();
void
Insert(size_t pos, T value);
void
Erase(size_t pos);
void
Show();
protected
:
T* _first;
T* _finish;
T* _endofstorage;
};
这里需要分清两个概念
Vectore -> 类名(声明构造函数或者析构函数时我们需要的是类名)
Vectore<T>
-> 类型(声明赋值运算符的重载时,我们返回值应该是一个类型)
声明和定义分离时,模板函数的定义
template
<
class
T>
Vector<T>::Vector() :_first(NULL), _finish(NULL), _endofstorage(NULL)
{}
template
<
class
T>
Vector<T>::~Vector()
{
delete
[] _first;
_first = _finish = _endofstorage = NULL;
}
template
<
class
T>
Vector<T>::Vector(
const
Vector<T>& v)
{
size_t size = v.Size();
_first =
new
T[Capacity()];
size_t i = 0;
for
(; i < size; ++i)
{
_first[i] = v._first[i];
}
_finish = _first + size;
_endofstorage = _first + v.Capacity();
}
调用方法
int main()
{
Vector<int> v1;
Vector<char> v2;
return 0;
}