目录
1、调用函数模板 隐式调用:正常函数传参即可调用 显示调用:函数名<类型名>(参数)
3、函数模板特殊写法:(1)缺省写法 (2)存在常量类型写法
一、模板简介
函数模板
模板:把类型作为未知量
声明模板的语法 template<typename _Ty> 注:_Ty只是代号可以替换
(1)引入模板
typename可以替换为class 如可以改写为template<class T>
//实际上两句为一句,只是为了好看才这样写
//template<typename _Ty> _Ty Max(_Ty a, _Ty b)
template<typename _Ty>//下面代码用到未知类型_Ty
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
//多模板
template<typename _Ty1,typename _Ty2>
void print( _Ty1 a, _Ty2 b)
{
cout << a << b << endl;
}
1、调用函数模板
隐式调用:正常函数传参即可调用
显示调用:函数名<类型名>(参数)
//使用的就是上面的函数
//隐士调用
cout << Max(1, 2) << endl;
cout << Max("s", "sad") << endl;
//显示调用 注意类型的匹配
cout << Max<string>("as", "sd");
print<string, string>("asa", "fd");
2、函数模板的两种形态:
(1)、 普通函数函数模板 (2) 、类中函数函数模板
普通函数模板就是之前的例子,下面的是类中函数模板
注:类外实现要写完整
class MM
{
public:
template<class _Ty> void print(_Ty data)
{
cout << data;
}//本质就是一行 为了好看会把代码拆开来 类外实现要写写全
template <class _Ty>void printData(_Ty data);
};
template <class _Ty>void MM::printData(_Ty data)
{
cout << data;
}
//隐式调用
MM mm;
mm.printData(1234);
3、函数模板特殊写法:(1)缺省写法 (2)存在常量类型写法
(1)缺省写法
template<typename _Ty1, typename _Ty2=int>
void print2(_Ty1 one, _Ty2 two)
{
cout << one << "\t" << two << endl;
}
int main()
{
//缺省:可以不传类型 但参数不可少
//函数模板显示调用
print2<string>("as", 123);
print2("123", 123);
return 0;
}
(2)存在传常量情况 不能传变量只能传常量
做了缺省可以隐式调用 否则必须显示调用
template<class _Ty1,size_t size>//size_t无符号整形别名
void printArray(_Ty1 array)
{
for (int i = 0;i < size;i++)//size可以直接使用
{
cout << array[i];
}
}
int main()
{
//存在传常量的情况 做了缺省可以隐式调用 否则必须显示调用
int array[3] = { 1,2,3 };
printArray<int*,3>(array);
return 0;
}
二、类模板
声明:template<class _Ty>
class MM{};
只要被修饰了就是模板类,不管有没有使用位置未知类型
类模板的调用(类外实现,继承,子类构造函数)
必须要显示调用
类模板不是一个实际类型,所以所有用到类名的地方都要使用:类名<未知类型>方法使用
多文件中,类模板的声明和实现要在一起,不能分开写
注意:1类外实现的写法变为了MM<_Ty>::
2继承的时候给父类赋值的写法
3 定义对象的写法
template<class _Ty>
class MM//准备一个父类
{
public:
MM() {}
MM(string name):name(name) {}
void print();
protected:
string name;
};
template<class _Ty>
void MM<_Ty>::print()//注意这里的声明变为了MM<_Ty>::
{
cout << "类模板" << endl;
}
//子类
template<class _Ty>
class Girl :public MM<_Ty>
{
public://子函数构造函再给父类赋值时需要加<_Ty>
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 << two << endl;
}
调用
int main()
{
//必须采用显示调用
MM<int> mm;
Girl<int> g("adas");
g.print();
Data<string, int> n("qwe", 21);
n.print();
return 0;
}
三、自定义类型做模板
关键在于运算符的重载
//准备一个数据类
class MM
{
public:
MM(string name, int age) :name(name), age(age) {}
friend ostream& operator<<(ostream& out,const MM& mm)
{
out << mm.name << "\t" << 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)
{
cout << one;
}
template<class _Ty>
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
int main()
{
//函数模板传入自定义类型
print(MM("asds", 123));
MM x("asd", 13);
MM s("qwe", 17);
MM result=Max(x, s);//Max<MM>()
cout << result;
return 0;
}
以链表为例存入自定义数据类型的数据
//类模板
template<class _Ty>
class Node
{
public:
Node(_Ty data, Node<_Ty>* next) :data(data), next(next) {}
_Ty getData()
{
return data;
}
Node<_Ty>* getNext()
{
return next;
}
protected:
_Ty data;
Node<_Ty>* next;
};
template<class _Ty>
class List
{
public:
List()
{
headNode = nullptr;
}
void insertList(_Ty data)
{
headNode = new Node<_Ty>(data, headNode);
}
void printList()
{
Node<_Ty>* pMove = headNode;
while (pMove != nullptr)
{
cout << pMove->getData() << endl;
pMove = pMove->getNext();
}
cout << endl;
}
protected:
Node<_Ty>* headNode;
};
调用·
int main()
{
List<int> list;
list.insertList(1);
list.insertList(2);
list.printList();
//这里的MM就是一开始准备的数据类,其中<<在MM类中做了运算符重载
List<MM> list1;
list1.insertList(MM("as", 12));
list1.insertList(MM("qw", 16));
list1.printList();
return 0;
}
四、模板的嵌套
//准备两个类模板MM和Data
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 << endl;
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;
}
protected:
_Ty1 one;
_Ty2 two;
};
template<class _Ty>
void print(_Ty data)
{
cout << data << endl;
}
int main()
{
//隐士调用
print(MM<string, int>("asd", 123));
//显示调用
print<MM<string, int>>(MM<string, int>("asd", 123));
Data<MM<string, int>, MM<double, int>>//显示调用
data(MM<string, int>("ASD", 123), //定义data并赋值
MM<double, int>(12.3, 12));
data.print();
return 0;
}
五、类模板的特化
初始的类模板
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 MM<_Ty,_Ty> //特化产生的类类名要用:类名<类型>方式使用
{
public:
MM(_Ty one, _Ty two) :one(one), two(two) {}
void print()
{
one.print();
two.print();
}
protected:
_Ty one;
_Ty two;
};
class Data
{
public:
Data(int one, int two) :one(one), two(two) {}
void print()
{
cout << one << "特殊化 " << two << endl;
}
protected:
int one;
int two;
};
int main()
{
MM<Data, Data> mm3(Data(1, 2), Data(2,3));
mm3.print();
return 0;
}
完全特化 依旧是模板类 类型变为已知 元组容器
template<>
class MM<string, string>
{
public:
MM(string one, string two) :one(one), two(two) {}
void print()
{
cout << one << "完全特化 " << two << endl;
}
protected:
string one;
string two;
};
int main()
{
MM<string, string> mm4("sad", "zxc");
mm4.print();
return 0;
}
六、函数模板的重载
隐士调用优先调用类型一致的函数
字符传优先解析为char*
隐士调用中当2个模板同时成立,优先调用类型相似度高的
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()
{
//显示调用 100%调用模板
//隐士调用优先调用类型一致的函数
//字符传优先解析为char*
print(12, string("qwe"));
print(12, "qwe");
//隐士调用中当2个模板同时成立,优先调用类型相似度高的
print(12, 12);
}