泛型编程:模板的基本使用
1.交换数字
通用写法
void mySwap(int &a,int &b)
{
int temp = a;
a =b;
b= temp;
}
void test01()
{
int a = 10;
int b = 20;
mySwap(a,b);
cout<<a<<endl;
cout<<b<<endl;
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
20
10
Process finished with exit code 0
泛型编程
1.自动类型推导,必须有参数类型才可以推导,不允许产生二义性。
//类型太多,逻辑相似
//类型参数化,泛型编程==模板技术
template <class T> //告诉编译器,下面出现T,不要报错,T为通用类型
void mySwapT(T &a,T &b)
{
T temp = a;
a =b;
b= temp;
}
void test02()
{
int a = 10;
int b = 20;
mySwapT(a,b);
cout<<a<<endl;
cout<<b<<endl;
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
20
10
Process finished with exit code 0
2.显示指定类型
mySwapT<int>(a,b);
3.模板必须要指定T才可以运行
下面这段程序报错,T无法推导其类型
template <typename T>
void mySwapT2()
{
}
void test03()
{
mySwapT2<>();
}
2.利用模板实现通用数组排序
template <class T>
void SwapT(T &a,T &b)
{
T temp = a;
a =b;
b= temp;
}
template <class T>
void mysort(T arr[],int len)
{
for (int i = 0; i <len; ++i)
{
int max = i;
for(int j = i+1;j<len;j++)
{
if(arr[max] <arr[j])
{
max = j;
}
}
if (max !=i)
{
//交换数据
SwapT(arr[max],arr[i]);
}
}
}
//输出数组元素
template <class T>
void printArray(T arr[],int len)
{
for(int i= 0;i<len;i++)
cout<<arr[i]<<" ";
cout<<endl;
}
void test04()
{
char arr[] = "helloworld";
int n = sizeof(arr)/sizeof(char);
mysort(arr,n);
printArray(arr,n);
}
3.函数模板与普通函数的区别及调用规则
template 必须紧跟函数体
1.区别
template <class T>
T myPlus(T a, T b)
{
return a+b;
}
int myPlus2(int a,int b )
{
return a+b;
}
void test05()
{
int a = 10;
int b = 20;
char c = 'c'; //a =97 c= 99
myPlus(a,b);
myPlus2(a,b);
// cout<<myPlus(a,c)<<endl; //错误 函数模板不可进行隐式类型转换
cout<<myPlus2(a,c); //普通函数可以进行隐式类型转换
}
2.普通函数和函数模板的调用规则
1.如果出现重载, 优先调用普通函数。
如果普通函数未实现,则报错
template <class T>
void myPrint(T a,T b)
{
cout<<"template print"<<endl;
}
void myPrint(int a,int b)
{
cout<<"common print"<<endl;
}
void test06()
{
int a = 10;
int b = 20;
//如果出现重载, 优先使用普通函数。
myPrint(a,b);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
Process finished with exit code 0
2.如果强制调用模板函数,则使用空参数列表
myPrint(a,b);
myPrint<>(a,b);
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print
Process finished with exit code 0
3.函数模板可以实现重载
template <class T>
void myPrint(T a,T b)
{
cout<<"template print"<<endl;
}
void myPrint(int a,int b)
{
cout<<"common print"<<endl;
}
template <class T>
void myPrint(T a,T b,T c)
{
cout<<"template reload print "<<endl;
}
void test06()
{
int a = 10;
int b = 20;
int c = 30;
//如果出现重载, 优先使用普通函数。
//如果普通函数未实现,则报错
myPrint(a,b);
//如果强制调用模板函数,则使用空参数列表
myPrint<>(a,b);
//模板函数重载
myPrint(a,b,c);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print
template reload print
Process finished with exit code 0
4.如果函数模板可以产生更好的匹配,那么优先调用函数模板
void test06()
{
int a = 10;
int b = 20;
int c = 30;
//如果出现重载, 优先使用普通函数。
//如果普通函数未实现,则报错
myPrint(a,b);
//如果强制调用模板函数,则使用空参数列表
myPrint<>(a,b);
//模板函数重载
myPrint(a,b,c);
char d = 'd';
char e = 'e';
myPrint(d,e);
}
调用函数模板不需要进行隐式类型转换
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
common print
template print
template reload print
template print
Process finished with exit code 0
4.模板机制
- 编译器并不是把函数模板处理成能够处理任何类型的函数
- 函数极板通过具体类型产生不同的函数
- 编译器对模板函数进行两次编译,在声明的地方对模板本身进行编译,在调用的
方对参数替换后的代码进行编译
5.模板的局限性及解决
通用模板有时无法完成函数体内的具体操作。
class Person
{
public: Person(string name,int age)
{
this->m_Name = name;
this->m_Age = age;
}
private:
string m_Name;
int m_Age;
};
template <class T>
bool myCompare(T &a ,T&b)
{
if(a > b)
return true;
else
return false;
}
//通过具体化类型定义,解决上述问题
void test07()
{
int a = 10;
int b = 20;
int ret = myCompare(a,b);
cout<<ret<<endl;
Person p1("tom",10);
Person p2("jerry",20);
int ret2 = myCompare(p1,p2);
cout<<ret<<endl;
}
ret为0,ret2运行失败
解决方案:
通过具体化自定义数据类型,解决上述问题
调用这个函数时,程序会优先调用匹配度高的
template<> bool myCompare<Person>(Person &a,Person &b)
{
if (a.m_Age>b.m_Age)
return true;
return false;
}
具体语法:template<>返回值 函数名 <具体类型>(参数)
6.类模板的基本使用
template <class NameType,class AgeType>
class Per
{
public:
Per(NameType name,AgeType age)
{
this->m_name = name;
this->m_age = age;
}
void showPer()
{
cout<<this->m_name<<endl;
cout<<this->m_age<<endl;
}
NameType m_name ;
AgeType m_age;
};
void test08()
{
//自动类型推导 类模板不支持
//Per per("jerry",50);
//显示指定类型
Per<string,int>per("jay",40);
per.showPer();
}
类模板可以有默认参数类型,函数模板不可以
template <class NameType,class AgeType = int>
7.函数的调用时机
class Person1
{
public:
void showPerson1()
{
cout<<"Person1"<<endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout<<"Person2"<<endl;
}
};
template <class T>
class myClass
{
public:
T obj;
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}
};
void test09()
{
myClass<Person1>m;
m.func1();
}
成功调用
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
Person1
Process finished with exit code 0
m.func2();// 报错
成员函数 一开始不会创建出来,而是在运行时才去创建
8.类模板做函数的参数
template <class NameType,class AgeType = int>
class PersonNew
{
public:
PersonNew(NameType name,AgeType age)
{
this->m_name = name;
this->m_age = age;
}
void showPer()
{
cout<<this->m_name<<endl;
cout<<this->m_age<<endl;
}
NameType m_name ;
AgeType m_age;
};
1.传入指定类型
void doWork(PersonNew<string,int>&p)
{
p.showPer();
}
void test10()
{
PersonNew<string,int>personNew("mj",10);
doWork(personNew);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
mj
10
Process finished with exit code 0
2.参数模板化
template <class T1,class T2>
void doWork2(PersonNew<T1,T2>&p)
{
p.showPer();
}
void test11()
{
PersonNew<string,int>p1("lb",20);
doWork2(p1);
}
G:\CSlrn\C++Code\Template\cmake-build-debug\Template.exe
lb
20
Process finished with exit code 0
3.整体类型化
template <class T>
void doWork3(T &p)
{
p.showPer();
}
void test12()
{
PersonNew<string,int>p2("cj",20);
doWork3(p2);
}
4.查看数据类型函数
//如何查看数据类型
template <class T1,class T2>
void doWork4(PersonNew<T1,T2>&p)
{
cout<<typeid(T1).name()<<endl;
p.showPer();
}
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE