函数模板
什么是模板:
把类型当作未知量来处理,可以忽略类型的影响。
申明模板方法:template<typename 类型代号>
存在多个未知数据类型template<typename 类型代号,typename 类型代号>
其中typename可以换成class
tmplate<class 类型代号>
调用函数模板:
隐式调用:正常函数传参即可调用
显示调用 :函数名<类型名>(参数)
函数模板的两种形态:
1.普通函数当作模板
2.类的成员函数是函数模板
函数模板特殊写法:
1.缺省写法
2.存在一个常量类型
#include<iostream>
using namespace std;
//int Max(int a, int b) {
// return a > b ? a : b;
//}
//string Max(string a, string b) {
// return a > b ? a : b;
//}
//引入模板概念template
template <typename _Ty>//标准格式
_Ty Max(_Ty a, _Ty b) {
return a > b ? a : b;
}
template<class _Ty1, class _Ty2>void print(_Ty1 a, _Ty2 b) {
cout << a << endl;
cout << b << endl;
}
//类的成员函数是函数模板
class Girl {
public:
template<class _Ty>void print(_Ty data) {
cout << data << endl;
}
template<typename _Ty>void printData(_Ty data);
protected:
string name;
int age;
};
template<typename _Ty>void Girl::printData(_Ty data) {//类中申明,类外实现前缀不能省略
cout << data << endl;
}
//缺省写法
template<class _Ty1, class _Ty2 = int>void printData(_Ty1 one, _Ty2 two) {
cout << one << "\t" << two << endl;
}
//存在传常量写法
template<class _Ty1, size_t size>void printArray(_Ty1 array) {//_Ty1=int*,size=3(必须显示调用,除废用缺省)
for (int i = 0; i < size; i++) {
cout << array[i];
}
cout << endl;
} //size_t无符号整形的别名
void testFunc() {
printData("string", 1231);
//可以类型缺省,但是参数不能少
printData<string>("string", 123);
int array[3] = { 1,2,3 };
printArray<int*,3>(array);
/*int size = 3;//不能传变量,只能传入常量,函数模板如果存在变量的情况下
printArray<int*,size>(array)*/
}
int main() {
cout << Max(1, 2) << endl;//隐式调用
cout << Max("string1", "string2") << endl;//隐式调用
cout << Max(1.1,2.5) << endl;//隐式调用
cout << Max<string>("abc", "def") << endl;//显示调用
print<string, string>("1234", "4321");
print<string, int>("1234", 4321);
//调用类中成员函数模板
Girl girl;
girl.print(123);
girl.print<string>("ILoveYou");
//模板函数也可以缺省
return 0;
}
类模板(用在数据结构上比较多)
如何生成一个类模板:
template<class _Ty>class MM{
public:
protected:
}
只要被template修饰了就是模板类型,至于是否用了未知类型,没有关系
类模板的调用:
必须采用显示调用
类模板不是一个实际的类,所以所有用到类名的地方,都需要使用类名<未知类型>方式使用
多文件中,类模板中的声明和实现一定是在一起的,不能分开写。
和函数模板一样可以传常量
#include<iostream>
using namespace std;
//template<>class Data {
//public:
//protected:
//};
template<class _Ty>class MM {
public:
MM(){}//构造函数正常写
MM(string name):name(name){}
void print();
protected:
string name;
};
//在类外实现
template<class _Ty>void MM<_Ty>::print() {
cout << "类模板" << endl;
}
//继承
template<class _Ty>class Girl :public MM<_Ty> {
public:
Girl(string name) :MM<_Ty>(name) {
}
protected:
};
template<class _Ty1, class _Ty2>class Data {
public:
Data(_Ty1 one,_Ty2 two):one(one),two(two){}
void print();
protected:
_Ty1 one;
_Ty2 two;
};
template<class _Ty1, class _Ty2>void Data<_Ty1,_Ty2>::print() {
cout << one << endl;
cout << two << endl;
}
int main() {
//MM mm;模板类直接创建对象报错
//必须采用显示调用
MM<int>mm1;
MM<string>mm2;
Girl<int> girl("loveyou");
Data<string, int> data1("张三", 20);
data1.print();
Data<int, int> data2(12, 21);
data2.print();
return 0;
}
?模板传入自定义类型
?基本自定义类型:
自定义类型也是模板:
模板传入自定义类型,关键点就在运算符重载
#include<iostream>
using namespace std;
class MM {
public:
MM(string name,int age):name(name),age(age){}
friend ostream& operator<<(ostream& out,const MM& mm) {
out << mm.name << " " << mm.age << endl;
return out;
}
bool operator>(MM& mm)const {
return this->age > mm.age;
}
protected:
string name;
int age;
};
template<class _Ty>void print(_Ty one){
// 二元"<<":没有找到接受“_Ty”类型的右操作数的运算符(或没有可接受的转换)
//对象不能直接打印
cout << one << endl;
}
template<class _Ty>_Ty Max(_Ty a,_Ty b) {
return a > b ? a : b;
}
template <class _Ty> class Node {
//using LPtype = Node<_Ty>;
public:
Node(_Ty data,Node<_Ty>* next):data(data),next(next){}
Node<_Ty>* getNext() {
return next;
}
_Ty getData() {
return data;//MM对象返回值是常属性,所以<<重载要加const!!!!
}
protected:
_Ty data;
//LPtype* next;
Node<_Ty>* next;
};
template<class _Ty>class List {
public:
List() {
headNode = nullptr;
}
void insertList(_Ty data) {
headNode = new Node<_Ty>(data, headNode);
}
void printData() {
Node<_Ty>* pMove = headNode;
while (pMove != nullptr) {
cout << pMove->getData() << endl;
pMove = pMove->getNext();
}
}
protected:
Node<_Ty>* headNode;
};
void testList(){
List<int> list;
list.insertList(1);
list.insertList(2);
list.insertList(3);
list.printData();
List<MM> mmList;
mmList.insertList(MM("小花", 21));
mmList.insertList(MM("小华", 12));
mmList.insertList(MM("晓华", 32));
mmList.printData();
}
int main() {
//函数模板传入自定义类型
print<int>(12);
print("Ilobeyou");
print(MM("mm", 19));
MM girl1("张三", 21);
MM girl2("李四", 25);
MM result = Max<MM>(girl1, girl2);//也可以隐式调用
cout << result;
testList();
return 0;
}
模板的嵌套(类)
明白类型是什么即可,可以适当运用using语法起别名,简化代码。
#include<iostream>
using namespace std;
template<class _Ty1, class _Ty2>class MM {
public:
MM(_Ty1 one,_Ty2 two):one(one),two(two){}
friend ostream& operator<<(ostream& out,const MM& mm) {
out << mm.one << " " << mm.two;
return out;
}
protected:
_Ty1 one;
_Ty2 two;
};
template<class _Ty1,class _Ty2>class Data {
public:
Data(_Ty1 one, _Ty2 two) :one(one), two(two) {}
void print() {
cout << one << " " << two << endl;
}
protected:
//MM<_Ty1, _Ty2> mmData;
_Ty1 one;
_Ty2 two;
};
void testFunc() {
//_Ty1类型是MM
//_Ty类型是MM<string,double>
Data<MM<string, int>, MM<string, double>> data(MM<string,int>("小强",18),MM<string,double>("大强",20.0));
data.print();
}
template<class _Ty>void print(_Ty data) {
cout << data << endl;
}
int main() {
print(MM<string, int>("晓华", 12));
print<MM<string, int>>(MM<string, int>("张三", 40));
using MMType = MM<string, int>;
print<MMType>(MMType("李四", 28));
testFunc();
return 0;
}
函数模板重载
#include<iostream>
using namespace std;
void print(int a,string b) {
cout << "普通函数" << endl;
}
template<class _Ty1, class _Ty2>void print(_Ty1 a, _Ty2 b) {
cout << "两个类型模板函数" << endl;
}
template<class _Ty>void print(_Ty a,_Ty b) {
cout << "一个类型模板函数" << endl;
}
int main() {
print<int, string>(12, "显示调用一定调用模板的");
print(21, string("优先调用适应的普通函数"));
//当两个模板同时成立,优先调用类型相似度高的那个
print(12, 12);
return 0;
}
类模板特化
局部特化:
完全特化:
#include<iostream>
#include<string>
using namespace std;
//两个未知类型
template<class _Ty1, class _Ty2>class MM {
public:
MM(_Ty1 one,_Ty2 two):one(one),two(two){}
void print(){
cout << one << " " << two << endl;
}
protected:
_Ty1 one;
_Ty2 two;
};
class Data {
public:
Data(int a,int b):a(a),b(b){}
void print() {
cout << a << " " << b << endl;
}
protected:
int a;
int b;
};
//局部特化,特殊化
template<class _Ty>class MM<_Ty,_Ty> {//特化产生的类,类名要用:类名<类型>方式使用
public:
MM(_Ty one, _Ty two) :one(one), two(two) {}
void print() {
//cout << one << " " << two << endl;
one.print();
two.print();
cout << "特殊化" << endl;
}
protected:
_Ty one;
_Ty two;
};
//完全特化(类型全部具体化)
//在折叠参数中有用
template<>class MM<string, string> {
public:
MM(string one,string two):one(one),two(two){}
void print() {
cout << "完全特化" << endl;
cout << one << " " << endl;
}
protected:
string one;
string two;
};
int main() {
MM<string, int>mm1("张三", 48);
//MM<string,string>mm2("李四","翠花");
MM<Data, Data> dMM(Data(1,2),Data(3,4));
dMM.print();
return 0;
}
|