泛型编程
泛型编程:是编写出不局限于特定数据类型的、通用的算法模型的代码。
#include <iostream>
int add(int a,int b){
return a + b;
}
double add(double a,double b){
return a + b;
}
int main() {
int a = add(2,4);
double b = add(1.2,3.3);
std::cout << a << std::endl;
std::cout << b << std::endl;
return 0;
}
向上面两个add函数,只是数据类型不同,函数的内容完全一样。如果每一种类型写一个这样的函数,int,float,unsinged int,double等这些都写一个函数。
弊端:
1.加大程序的大小
2.程序员的工作量大大提高,重复造轮子。
模板
模板是泛型编程的基础。
函数模板
定义一个函数模板
#include <iostream>
using namespace std;
//int add(int a,int b){
// return a + b;
//}
//
//double add(double a,double b){
// return a + b;
//}
template<typename T>
T add(T a,T b){
return a + b;
}
int main() {
cout << add<int>(1,2) << endl;
cout << add<double>(1.1,2.2) << endl;
return 0;
}
template<模板参数列表>
1.模板参数可以用class
template<class T>
2.也可以用typename
template<typename T>
注意:函数模板定义并不会导致编译器生成相关的代码,只有调用这个函数模板时,才会生成特定的函数代码。
类模板
template<typename T>
class A{
public:
T sub(T a,T b){ //类模板里面的函数定义:直接使用模板参数,没有啥注意的
return a - b;
}
A();
private:
int sum;
};
template<typename T> //类模板外的函数定义:需要将template<参数列表>带上,
A<T>::A():sum(0){ //并且类名后面需要加:<所有参数>。多个参数用逗号隔开。
cout << "构造函数" << endl;
}
int main() {
A<int> a;
cout << a.sub(1,4) << endl;
//cout << add<int>(1,2) << endl;
return 0;
}
注意:同样,类模板实例化后,若成员函数没有被调用,该成员函数不会被实例化。
类的内置-类型成员
template<typename T>
class A{
public:
typedef T* myPoint; //typedef定义一个内置类型成员
A();
T sub(T a,T b){ //类模板里面的函数定义:直接使用模板参数,没有啥注意的
return a - b;
}
myPoint myGET();
private:
int sum;
};
template<typename T> //类模板外的函数定义:需要将template<参数列表>带上,
A<T>::A():sum(0){ //并且类名后面需要加:<所有参数>。多个参数用逗号隔开。
cout << "构造函数" << endl;
}
template<typename T>
typename A<T>::myPoint A<T>::myGET(){
return ∑
}
用typename的另一个作用:
用于标明类型成员。
默认模板参数
默认值参数(统一规则):从有默认值参数的位置开始,它后面的参数都必须有默认值。
类模板的默认参数使用
template<typename T = int,int a = 3>
class A{
......
}
使用的方式:
可以只写前面的一个或者多个 参数,其他用默认参数:
A <string> a;
也可以都写:
A<string,5> a;
函数模板的默认参数使用
template<typename T = double>
T add(T a,T b){
return a + b;
}
上面修改add函数模板。
默认参数为int。
可以这样使用:
add(1,1);(即使不写默认模板参数,也可以这么做,编译器会根据实参类型自动推导出模板参数类型)
模板的显示实例化
含有模板的.h文件在多个不同的.cpp文件中被使用,因为每个.cpp文件是独立的,因此每个.obj文件中都含有一份模板。
这样会导致程序代码占用内存大。
解决办法:
1.在某个.cpp文件中定义模板:
template A<double>;
2.在其他使用该实例化模板的.cpp文件中,用extern声明
extern template A<double>;
extern 会告诉编译器这是个声明,在其他.cpp文件中已经有一个该类模板的实例化版本了。
注意:只能一处定义,可以多处声明。
缺点:使用template A<double>;实例化定义,系统会把类模板以及所有成员函数都实例化出来。
这样会增加编译的时间和代码长度。
根据优劣合理的分析使用。
模板特化
为什么需要特化?
下面由代码讲解。
全特化:模板参数全部特化。
偏特化:模板参数部分特化。
类模板全特化
#include <iostream>
using namespace std;
template<typename T,typename U>
class Student{
public:
Student(){
cout << "泛型模板" << endl;
}
void Show(T a){
cout << a << endl;
}
};
template<> //全特化,即里面的参数都特化到了类,故<>中为空
class Student<string,int>{
public:
Student(){
cout << "Student<string,int>特化版本" << endl;
}
void show(string a){
cout << a << endl;
};
};
int main() {
Student<int ,int> libai;
libai.Show(23);
Student<string,int> sunwukong;
sunwukong.show("sunwukong");
return 0;
}
运行结果:
泛型模板
23
Student<string,int>特化版本
sunwukong
类模板偏特化
1.参数数量上的偏特化
2.参数范围上的偏特化
#include <iostream>
using namespace std;
template<typename T,typename U>
class Student{
public:
Student(){
cout << "泛型模板" << endl;
}
void Show(T a){
cout << a << endl;
}
};
template<> //全特化,即里面的参数都特化到了类,故<>中为空
class Student<string,int>{
public:
Student(){
cout << "Student<string,int>特化版本" << endl;
}
void show(string a){
cout << a << endl;
};
};
template<typename U> //1.参数数量上的偏特化,只特化前面的T类型
class Student<string,U>{
public:
Student(){
cout << "Student<string,U>参数数量上的偏特化" << endl;
}
void show(string a){
cout << a << endl;
};
};
template<typename T,typename U> //2.参数范围上的偏特化:const ,指针,引用等都是参数范围上的偏特化
class Student<const T,const U>{
public:
Student(){
cout << "Student<const T,const U>参数范围上的偏特化" << endl;
}
void Show(T a){
cout << a << endl;
}
};
int main() {
Student<int ,int> libai;
libai.Show(23);
Student<string,int> sunwukong;
sunwukong.show("sunwukong");
Student<string,double> xiaohei;
xiaohei.show("xiaohei");
Student<const int,const int> xiaoming;
xiaoming.Show(22);
return 0;
}
}
运行结果:
泛型模板
23
Student<string,int>特化版本
sunwukong
Student<string,U>参数数量上的偏特化
xiaohei
Student<const T,const U>参数范围上的偏特化
22
函数模板全特化
#include <iostream>
using namespace std;
template<typename T,typename U>
void show(T a,U b){
cout << a << endl;
cout << b << endl;
}
template<>
void show<double,double>(double a,double b){
cout << "double:" << a << endl;
cout << "double:" << b << endl;
}
//template<typename U> //error:non-class, non-variable partial specialization ‘show<double, U>’ is not allowed
//void show<double,U>(double a,U b){
// cout << "偏:double:" << a << endl;
// cout << "偏:double:" << b << endl;
//}
int main() {
show<int,int>(1,2);
show<double,double>(1.1,2.2);
show<double,int>(1.3,2);
return 0;
}
函数模板偏特化
函数模板不能偏特化。