模版特化:
模板的“特化”(实例化),它发生在编译期,无论一个模板被实例化多少次,都不会影响最终结果,但是这会浪费编译的时间.不知道隐式特化是啥东西.但是显式特化的意思是:当一类东西中出了一渣滓的时候,为了对外接口的统一,或者说是为了家丑不可外扬,有必要把它单独拿出来写一下,然后使他可以和这个类中的所有东西步伐一致.为了需要,针对特定的类型,需要对模板进行特化,也就是特殊处理, 是为模板的特化.
类模板
说明:
类模板就是建立一个通用类,其数据成员的类型、成员函数的返回类型和参数类型都不具体指定,用一个虚拟类型来代表.当使用类模板建立对象时,系统会根据实参的类型来取代类模板中的虚拟类型从而实现不同类的功能
模板参数:
对于函数模板和类模板,模板参数并不局限于类型,普通值也可以作为模板参数.在基于类型参数的模板中,你定义了一些具体细节未加确定的代码,直到代 码被调用时这些细节才被真正确定.然而,在这里,我们面对的这些细节是值(value),而不是类型.当要使用基于值的模板时,你必须显式地指定这些值, 才能够对模板进行实例化,并获得最终代码.在这一章里,我们将使用一个新版本的stack类模板来叙述这个特性.另外,我们还给出了一个非类型函数模板参 数的例子,并且讨论了这一技术的某些限制
定义格式:
格式一:
template <typename 类型参数1,typename 类型参数2, ... ,参数类型 参数1,参数类型 参数2, ...>
class 类名
{
类成员声明
};
格式二:
template <class 类型参数1,class 类型参数2, ... ,参数类型 参数1,参数类型 参数2, ...>
class 类名
{
类成员声明
};
类成员声明:
要求
在类成员声明里,成员数据类型、成员函数的返回类型和参数类型前面需加上类型参数.在类模板中成员函数既可以定义在类模板内,也可以定义在类模板外,在外部定义类模板的成员函数外时 C++ 有这样的规定:需要在成员函数定义之前进行模板声明,且在成员函数名之前加上“类名<类型参数>::”
格式
对应格式一:
template <typename 类型参数1,typename 类型参数2, ... ,参数类型 参数1,参数类型 形参2, ...>
返回类型 类名<类型参数1,参数类型2, ... ,形参1,形参2, ...>::函数名(形参)
{
函数体
}
对应格式二:
template <class 类型参数1,class 类型参数2, ... ... ,参数类型 形参1,参数类型 形参2, ...>
返回类型 类名<类型参数1,参数类型2, ... ,形参1,形参2, ...>::函数名(形参)
{
函数体
}
实例对象声明格式:
- 类模板名<实际类型1,实际参数2, ... ,实参1,实参2, ...> 对象名;
- 类模板名<实际类型1,实际参数2, ... ,实参1,实参2, ...> 对象名(构造函数实参);
注意:
- 在一个类模板的各个实例之间没有联系,形成一个个独立的类
- 模板的实例可用在一般类可以用的任何地方,用模板类实例定义的对象和一般的对象用法完全相同
- 实例化的时机:在需要时实例化,比如定义指针或者引用时不需要实例化,定义具体的变量或者常量时不会实例化,而访问对象的成员时会实例化
例子:
类模板(在类内部声明成员函数):
// demo.h 文件内容 *******************************
#include<iostream>
using namespace std;
template<class type>
class A
{
private:
type a;
type b;
public:
A(type x,type y)
{
a=x;
b=y;
cout<<"new instance"<<endl;
cout<<"the value of a is "<<a<<endl;
cout<<"the value of b is "<<b<<endl<<endl;
}
};
// main.cpp 文件内容 *******************************
#include"demo.h"
void main()
{
int x=3,y=6;
double a=9.45,b=10.23;
A<int> app1(x,y);
A<double> app2(a,b);
system("pause");
}
/*****************************************
输出结果:
new instance
the value of a is 3
the value of b is 6
new instance
the value of a is 9.45
the value of b is 10.23
请按任意键继续. . .
*****************************************/
类模板(在类外部声明成员函数,成员函数只能在 .h 文件中定义,要是在 .cpp 中定义编译时候会出现链接错误):
// demo.h 文件内容 *******************************
#include<iostream>
using namespace std;
template<class type>
class A
{
private:
type a;
type b;
public:
A(type x,type y);
void max();
};
template<class type>
A<type>::A(type x,type y)
{
a=x;
b=y;
cout<<"new instance"<<endl;
cout<<"the value of a is "<<a<<endl;
cout<<"the value of b is "<<b<<endl;
}
template<class type>
void A<type>::max()
{
cout<<a<<">"<<b<<"? "<<(a>b?"yes":"no")<<endl;
}
// main.cpp 文件内容 *******************************
#include"demo.h"
void main()
{
int x=3,y=6;
double a=9.45,b=10.23;
A<int> app1(x,y);
app1.max();
cout<<endl;
A<double> app2(a,b);
app2.max();
system("pause");
}
/******************************************
输出结果:
new instance
the value of a is 3
the value of b is 6
3>6? no
new instance
the value of a is 9.45
the value of b is 10.23
9.45>10.23? no
请按任意键继续. . .
******************************************/
以上都是用关键字 class 现在举个用 typename 关键字的例子但是其与 class 关键字没有什么差别:
// demo.h 文件内容 *******************************
#include<iostream>
using namespace std;
template<typename type>
class A
{
private:
type a;
type b;
public:
A(type x,type y)
{
a=x;
b=y;
cout<<"new instance"<<endl;
cout<<"the value of a is "<<a<<endl;
cout<<"the value of b is "<<b<<endl<<endl;
}
};
// main.cpp 文件内容 *******************************
#include"demon.h"
void main()
{
int x=3,y=6;
double a=9.45,b=10.23;
A<int> app1(x,y);
A<double> app2(a,b);
system("pause");
}
/*****************************************
输出结果:
new instance
the value of a is 3
the value of b is 6
new instance
the value of a is 9.45
the value of b is 10.23
请按任意键继续. . .
*****************************************/
带有默认类型参数的类模板:
// demo.h 的文件内容 *****************************
#include<iostream>
using namespace std;
template<class type = int> // type 的默认类型参数为 int;
class A
{
private:
type a;
type b;
public:
A(type x,type y);
};
template<class type>
A<type>::A(type x,type y)
{
a=x;
b=y;
cout<<"new instance"<<endl;
cout<<"the value of a is "<<a<<endl;
cout<<"the value of b is "<<b<<endl;
}
// main.cpp 的文件内容 ****************************
#include"demo.h"
void main()
{
int x=3,y=6;
double a=9.45,b=10.23;
A<> app1(x,y);
cout<<endl;
A<double> app2(a,b);
system("pause");
}
/*******************************************
输出结果:
new instance
the value of a is 3
the value of b is 6
new instance
the value of a is 9.45
the value of b is 10.23
请按任意键继续. . .
*******************************************/
带有参数的类模板:
// demo.h 文件内容 *******************************
#include<iostream>
using namespace std;
template<class type,int a_x = 0>
class A
{
private:
type a;
type b;
int c;
public:
A(type x,type y);
void max();
};
template<class type,int a_x>
A<type,a_x>::A(type x,type y)
{
a=x;
b=y;
c = a_x;
cout<<"new instance"<<endl;
cout<<"the value of a is "<<a<<endl;
cout<<"the value of b is "<<b<<endl;
cout<<"the value of c is "<<c<<endl;
}
// main.cpp 文件内容 ******************************
#include"demo.h"
void main()
{
int x=3,y=6;
double a=9.45,b=10.23;
A<int,5> app1(x,y);
cout<<endl;
A<double,10> app2(a,b);
system("pause");
}
/*******************************************
输出结果:
new instance
the value of a is 3
the value of b is 6
the value of c is 5
new instance
the value of a is 9.45
the value of b is 10.23
the value of c is 10
请按任意键继续. . .
*******************************************/
友元类模板:
#include <iostream>
#include <cstdlib>
using namespace std;
template<class T2>
class B; //友元类的向前声明
template<class T1>
class A //拥有友元类的类的定义
{
private:
T1 y;
public:
A(T1 a):y(a){}
template<class T2>
friend class B;
};
template<class T2>
class B //友元类的定义
{
private:
T2 x;
public:
B(T2 a):x(a){};
template<class U>
void show(A<U> &a)
//这里的模板类型参数名可以与模板类 A 定义时候使用的模板参数名不一样
{
cout<<"the value of A::y is "<<a.y<<endl;
cout<<"the value of B::x is "<<x<<endl;
}
};
void main()
{
A<int> a(5);
B<double> b(10.20);
b.show(a);
system("pause");
}
/******************************************
输出结果为:
the value of A::y is 5
the value of B::x is 10.2
请按任意键继续. . .
******************************************/
函数模板
说明:
函数模板就是建立一个通用的函数,其参数类型和返回类型不具体指定,用一个虚拟的类型来代表
声明格式:
格式一:
template<typename 类型参数1,typename 类型参数2, ... >
返回类型 函数名(模板形参表)
{
函数体
}
格式二:
template<class 类型参数1,class 类型参数2, ... >
返回类型 函数名(模板形参表)
{
函数体
}
说明:
template 是一个声明模板的关键字,类型参数一般用T这样的标识符来代表一个虚拟的类型,当使用函数模板时,会将类型参数具体化. typename 和 class 关键字作用都是用来表示它们之后的参数是一个类型的参数.只不过 class 是早期 C++ 版本中所使用的,后来为了不与类产生混淆,所以增加个关键字 typename
注意:
- 函数模板也可被声明为 inline 或 extern ,但把指示符放在模板参数后
- 在函数模板定义中声明的对象或类型不能与模板参数同名
- 模板类型参数名可以被用来指定函数模板的返回值
- 模板参数名在同一模板参数表只能使用一次,但在多个函数模板声明定义可使用多次
- 在定义函数模板时要注意的一点是在 template 语句和函数模板定义语句之间是不允许插入其他的语句的,函数模板也可以重载
- 当模板函数和同名的非模板函数重载时,首先寻找与参数类型完全匹配的非模板函数,找到了,则调用它,如果没找到,则寻找函数模板,找到后具体化函数模板,而后调用该模板函数
模板函数与函数重载:
模板函数类似于重载函数,但两者有很大区别:函数重载时,每个函数体内可以执行不同的动作,但同一个函数模板实例化后的模板函数都必须执行相同的动作
工作原理:
在函数模板被调用时,编译器根据实际参数的类型确定模板参数T的类型,并自动生成一个对应的函数,即模板函数.模板参数的类型不同,生成的模板函数也不同.
例子:
函数模板:
#include<iostream>
using namespace std;
//函数模板声明
template<class T,class T2>
void output(T x,T2 y);
//主函数定义
void main()
{
double a = 7.09;
int b=5;
output(a,b);
output(b,a);
system("pause");
}
//函数模板定义
template<class T,class T2>
void output(T x,T2 y)
{
cout<<x<<" "<<y<<endl;
}
/************************************
输出结果:
7.09 5
5 7.09
请按任意键继续. . .
************************************/
模板函数和同名的非模板函数重载:
#include<iostream>
template<class T>
void max(T x,T y)
{
std::cout<<x<<">"<<y<<"? "<<(x>y?"yes":"no")<<std::endl;
}
void max(int x,int y)
{
std::cout<<x<<">"<<y<<"? "<<(x>y?"yes":"no")<<std::endl;
}
void main()
{
double a = 7.09 , b = 10.22;
long c = 8,d = 9;
int e = 10,f = 5;
max(a,b); //调用的是重载函数模板 void max(T x,T y)
max(c,d); //调用的是重载函数模板 void max(T x,T y)
max(e,f); //调用的是重载函数 void max(int x,int y)
system("pause");
}
/***************************************
输出结果:
7.09>10.22? no
8>9? no
10>5? yes
请按任意键继续. . .
***************************************/
在函数外部友元函数模板:
#include <iostream>
using namespace std;
template<class Type> class A
{
public:
A(Type b):a(b){}
template<class Type>
friend void output(const A<Type>& b);
Type a;
};
//在类外部定义友元函数
template<class Type>
void output(const A<Type>& b)
{
cout<<b.a<<endl;
}
int main(void)
{
A<int> a(10);
output(a);
system("pause");
}
// 输出结果为: 10
在函数内部友元函数模板:
#include <iostream>
using namespace std;
template<class Type> class A
{
public:
A(Type b):a(b){}
//在类内部定义友元函数
friend void output(const A& a){cout<<a.a<<endl;}
/******************************************************
等价形式:
template<class T>friend void output(const A<T>& a){cout<<a.a<<endl;}
这里的模板参数名可以与类声明中模板参数变量名不一样
******************************************************/
Type a;
};
int main(void)
{
A<int> a(10);
output(a);
system("pause");
}
// 输出结果为: 10
模板友元的另一种声明格式(向前声明):
#include <iostream>
using namespace std;
template<class Type> class A; //向前声明
template<class Type> void output(const A<Type>& b); //友元函数声明
/******************************************
//当然也可以是定义:
template<class Type>
void output(const A<Type>& b)
{
cout<<b.a<<endl;
}
******************************************/
template<class Type> class A
{
public:
A(Type b):a(b){}
friend void output<>(const A& b);
/******************************************
上面声明的等价形式:
friend void output<>(const A<Type>& b);
friend void output<Type>(const A<Type>& b);
******************************************/
Type a;
};
//在类外部定义友元函数
template<class Type>
void output(const A<Type>& b)
{
cout<<b.a<<endl;
}
int main(void)
{
A<int> a(10);
output(a);
system("pause");
}
// 输出结果为: 10