泛型初步
由于C++是静态强类型语言,所以变量一经创建,则类型不得更改。如果我们希望创建一种应用广泛地复数类型,那么相应地需要基于int、float、double这些基础类型逐一创建,十分麻烦。泛型编程便是为了简化这一过程而生。
能够容纳不同数据类型作为成员的类被成为模板类,其基本方法为在类声明的上面加上一行模板声明代码
template<typename T>
class myClass{};
其调用过程为myClass<T> m;
列举案例如下
#include<iostream>
using namespace std;
template<typename C>
struct Abstract{
C real; //real为C类型
C im;
Abstract(C inReal, C inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout<<"Abstract:"<<real<<"+"<<im<<"i"<<endl;
};
Abstract& multi(Abstract val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
};
};
int main(){
Abstract<float> fTemp{1,2};//C类型为float
fTemp.multi(fTemp);
fTemp.printVal();
system("pause");
return 0;
}
函数模板
当然,上述multi并不能实现两个不同类型的Abstract之间的相乘,所以可以将multi函数改为
template<typename T>
Abstract<C>& multi(Abstract<T> val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
这样就能够实现如下功能。
int main(){
Abstract<float> fTemp{1,2};
Abstract<int> iTemp{1,2};
fTemp.multi(iTemp);
fTemp.printVal();
getReal(fTemp);
system("pause");
return 0;
}
友元
模板类具备一部分普通类的性质,比如struct和class的区别,public、protected、private的性质,以及友元等。模板的声明特性也可以应用在函数中,例如
#include<iostream>
using namespace std;
template<typename C>
class Abstract{
C real;
C im;
public:
Abstract(C inReal, C inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout<<"Abstract:"<<real<<"+"<<im<<"i"<<endl;
};
Abstract& multi(Abstract val){
C temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
template<typename T> friend void getReal(Abstract<T> num); //声明友元
};
template<typename C>
void getReal(Abstract<C> num){
cout<<num.real<<endl;
}
int main(){
Abstract<float> fTemp{1,2};
fTemp.multi(fTemp);
fTemp.printVal();
getReal(fTemp);
system("pause");
return 0;
}
需要注意的一点是,在模板类中声明友元,其前缀中的类型标识不得与已有的类型标识重复,否则编译无法通过。
由于函数模板可以针对不同的数据类型进行求解操作,是对函数或者方法实例的抽象,所以又被称为算法。
模板参数
如果将模板理解为一种类型声明的函数,那么模板也应该具备一些函数具备的功能。首先其模板参数中可以包含实际类型参数,例如
template<typename T, int max>
class Test{}
其调用时可以写为
`
Test<int,256> pixel;
模板同样支持默认参数,即可以实现如下形式
template<typename T=int, int max=256>
class Test{}
Test pixle;
除了数据类型、值之外,模板本身也可以作为模板参数,例如下面的形式是合法的。
template<typename T, template<typename> class C>
struct Test{
C<T>* val;
Test(C<T>* inVal){
val = inVal;
}
};
int main(){
Abstract<int> fTemp{1,2};
Test<int,Abstract> test(&fTemp);
test.val->printVal();
system("pause");
return 0;
}
其结果为
PS E:\Code\cpp> g++ .\generic.cpp
PS E:\Code\cpp> .\a.exe
Abstract:1+2i
请按任意键继续. . .
需要注意的一点是,在模板类中定义的模板类,需要进行实例化,否则会出现错误,所以在Test中,以指针形式创建了模板类。
类型函数
以数据类型为输入或输出的函数即为类型函数,在C语言中,sizeof便是一种类型函数,其输入为数据类型,输出为数据类型所需要的内存空间。
在C++11中,using可以实现数据类型赋予的功能,其使用方法与typedef相似
template<typename T>
struct Test{
using type = T;
}