模板就是生成一个通用的函数,这个函数可以接受任意数据类型的参数,可以返回任意类型的值。
模板是泛型编程的基础。所谓泛型编程就是编写与类型无关的逻辑代码,是一种强大的复用方式。
template1 , class 形参2,...>
返回类型 函数名(形参表)
{
// ;
}
template1 , typename 形参2,...>
返回类型 函数名(形参表)
{
// ;
}
模板形参定义class和typename是完全等价的,没有区别,所以你可以任意使用,但是不要两个混搭,让人看着不舒服。
eg:
void Swap(int *x1,int *x2)
{
int tmp = *x1;
*x1 = *x2;
*x2 = tmp;
}
void Swap(int **x1, int **x2)
{
int *tmp = *x1;
*x1 = *x2;
*x2 = tmp;
}
int main()
{
int a = 1;
int b = 2;
Swap(&a, &b);
int *p1 = &a;
int *p2 = &b;
Swap(&p1, &p2);
return 0;
}
根据上面例子看出:当你想进行两个整型交换时,是不是要写一个交换函数,当你想交换两个指针,又要写一个交换函数,那么你想交换两个字符串是不是又要写,为了解决这种麻烦,c++有了模板的这个概念,
template
void Swap(T *x1, T* x2)
{
T tmp = *x1;
*x1 = *x2;
*x2 = tmp;
}
这就是模板,它不关注你具体需要的类型,它会根据你的需求确定不同的函数类型执行不同的代码(这叫做模板函数实例化)。并且在c++库中交换函数swap也是用模板实现的。
重要的一点:编译时不会编译模板函数大括号里面的内容,那是因为模板函数还没有实例化,因为不知道函数形参类型,所以根本不能在堆栈上开辟空间。
//实例化调用
void Test()
{
int a = 1;
int b = 2;
Swap(&a,&b);//这叫做隐式实例化调用,需要系统自己推演实例化类型。
Swap<int>(&a,&b);//这叫做显示实例化,不需要推演就可以直接调用。
}
eg:
void show(int a, int b)
{
cout << "show()的普通函数" << endl;
}
template <class T>
void show(T a,T b)
{
cout << "默认模板函数" << endl;
}
template <class T1, class T2>
void show(T1 a,T2 b)
{
cout << "不同类型的模板函数" << endl;
}
template <class T>
void show(T a,T b)
{
cout << "默认模板函数" << endl;
}
template <class T1, class T2>
void show(T1 a,T2 b)
{
cout << "不同类型的模板函数" << endl;
}
template1, class 形参名2, ...,class 形参名n>
class 类名
{
//类定义;
};
template
class A
{
public:
A()
{}
protected:
T _a;
};
int main()
{
A<int>a;//必须传类的类型,否则在实例化时不能给对象a开辟空间大小
return 0;
}
模板参数不仅可以定义为类型还可以定义为固定类型的常量值。
模板类与模板函数都可以用非类型形参。
template<class T,int n>
void sum(T a,int n)
{
T i = a;
T sum = 0;
for (i=a; i <= n; ++i)
{
sum += i;
}
cout << sum << endl;
}
template<class T,int MAXSIZE>
class SeqList
{
public :
SeqList();
private :
T _array [MASIZE];
int _size ;
};
void Test()
{
sum<int, 3>(0, 3);
SeqList<int,10>S;
}
规则
template<class T,int MAXSIZE>
class List{
private:
T array[MAXSIZE];
public:
void show()
{
//;
}
};
const int num1 = 9; ;//全局变量
static int num2= 9; ;//全局变量
void Test()
{
const int num3 = 9; ;//局部变量
List<int,num1> list; //正确
List<int,num2> list; //错误
List<int,num3> list; //正确
}
//再看一个关于指针和字符串比较特别的例子
template<char const* name>
class pointer
{
};
char a[] = "aa";;//全局变量
char *b = "aa";//全局变量
char *const c = "aa";//全局变量,顶层指针,指针常量
void Test()
{
char d[] = "aa";//局部变量
pointer<"aa"> p1;//错误
pointer p2;//正确
pointer p4;//错误,error C2975:“pointer”的模板参数无效,应为编译时常量表达式
pointer p5;//错误,error C2970: “c”: 涉及带有内部链接的对象的表达式不能用作非类型参数
pointer p3;//错误,局部变量不能用作非类型参数
}