什么是模板?
把类型当做未知量来处理的行为叫做模板 写的函数或者类,不因为数据类型的改变,而要修改代码--->数据类型改变,依然适用于原来的代码(代码功能依旧可以使用)
-
忽略类型的影响
-
求(int类型、string类型...)最大值
-
因为数据类型的不同,需要写多个相同的函数--->虽然函数体是一样的,但是类型不同导致的额外代码
//求int类型的最大值
int Max(int a,int b)
{
return a > b ? a : b;
}
//求string类型的最大值
string Max(string a,string b)
{
return a > b ? a : b;
}
声明模板的语法 template <typename _Ty>
引入模板,把类型当作未知量
? Max(? a,? b) //引入模板 把类型当作未知量 未知类型|未知参数|函数体相同
template <typename _Ty>//template告诉编译器下面代码用到了一个未知类型_Ty 把_Ty当作类型去用
_Ty Max(_Ty a, _Ty b) //typename可以换成class
{
return a > b ? a : b;
}
存在单个未知类型
//单个未知类型
template <typename _Ty> //固定语法
_Ty Max(_Ty a, _Ty b) //_Ty:未知类型 a & b:未知参数
{
return a > b ? a : b; //函数体一样
}
template <typename _Ty> _Ty Max(_Ty a, _Ty b)
//或
template <typename _Ty>
_Ty Max(_Ty a, _Ty b)
/*两种都可以 第二种情况更美观
_Ty 随便改,就是类型代号*/
对于函数来说可以存在单个未知类型,也可以存在多个未知类型
//多个未知类型
template <typename _Ty1,typename _Ty2 > //存在多个未知类型 用 , 做间隔
void print(_Ty1 one,_Ty2 two) //如果还需要返回值可以_Ty3
{
cout<< one << endl;
cout<< two << endl;
}
int main()
{
//传两个一样的类型
print<string, string>("string1", "string2");
//传不同的类型
print<string, int>("string1", 1234);
}
/*输出*/
string1
string2
string1
1234
调用函数模板
调用函数模板 ---> 一个函数写了多个函数的功能,不因为类型的改变,需要把函数重写
-
隐式调用:正常的函数传参即可调用,不用管数据类型--->不需要显式传参
-
显示调用:函数名<类型名>(参数) ---> 需要显式传参
-
常用的函数 & 函数体相同的函数,一般使用函数模板来做
隐式调用
template <typename _Ty>
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
int main()
{
//隐式调用
cout << Max(1, 2) << endl;
cout << Max("string", "string1") << endl;
cout << Max(1.1, 2.3) << endl;
}
/*输出*/
2
string
2.3
显式调用
-
显式传入类型,遵守函数调用的规定,实参与形参类型一致
template <typename _Ty>
_Ty Max(_Ty a, _Ty b)
{
return a > b ? a : b;
}
int main()
{
//显示调用 传入string类型 加两个string类型参数即可
cout << Max<string>("abc","abd") << endl;
}
/*输出*/
abd
/*传参过程|默认传入3个参数*/
_Ty = string
a = "abc"
b = "abd"
两个未知类型的显示调用
template <typename _Ty1,typename _Ty2 >
void print(_Ty1 one,_Ty2 two)
{
cout << one << endl;
cout << two << endl;
}
int main()
{
//传入两个一样的类型
print<string,string>("string1","string2");
//传入不同的类型 模板传什么类型,参数也要与之匹配
print<string,int>("string1",1234);
}
/*输出*/
string1
string2
string1
1234
函数模板的两种形态
-
普通函数当做函数模板(上面的代码已经证实)
-
类的成员函数是函数模板(用法和普通函数一样)
类的成员函数是函数模板
class MM
{
public:
template <class _Ty> //类中的成员函数是函数模板和普通函数用法一样
void print(_Ty data)
{
cout << data << endl;
}
protected:
string name;
int age;
};
int main()
{
MM mm; //构造一个对象调用
mm.print(123); //隐式调用
mm.print<string>("ILoveyou"); //显式调用
}
/*输出*/
123
ILoveyou
类的成员函数的方式可以在类中声明,在类外实现,在类外实现不能省略 template 这一块
class MM
{
public:
template <class _Ty>
void printData(_Ty data);
protected:
string name;
int age;
};
//在类外实现不能省略template这一块
template <class _Ty>
void MM::printData(_Ty data)
{
cout << data << endl;
}
int main()
{
MM mm;
mm.printData(12344);
}
/*输出*/
12344
函数模板特殊的写法
-
函数模板与函数传参一样,可以缺省处理
-
存在常量类型
函数模板缺省
template <class _Ty1, class _Ty2 = int> //缺省为int类型
void printData(_Ty1 one, _Ty2 two)
{
cout << one << "\t" << two << endl;
}
void testFunc()
{
printData("string", 1234); //隐式调用无明显区别
printData<string>("ILoveyou", 12344);//函数模板缺省显式调用 可以不传类型但参数不能少
}
int main()
{
testFunc();
return 0;
}
/*输出*/
string 1234
ILoveyou 12344
//如果只传一个参数,如果第2个参数不传默认int类型,要传int类型的参数进去
存在传常量类型
/*存在传常量写法
int 或 size_t size_t: unsigned int 的别名(无符号整型) */
//打印数组(不同类型的)数组,传长度的参数
template <class _Ty1 ,size_t size=3> //做缺省,可以隐式调用
void printArray(_Ty1 array) //_Ty1 = int * 数组地址,size=3
{
for (int i = 0; i < size; i++) //声明1个变量size,意味着可以在函数里面使用这个变量
{
cout << array[i];
}
cout << endl;
}
void testFunc()
{
//函数模板中写了变量 没有做缺省必须显示调用
int testarray[3] = { 1,2,3 };
printArray<int*,3>(testarray);
//没有做缺省必须显式调用,做了缺省可以隐式调用
printArray(testarray);
/*函数模板不能传入变量,只能传入常量
int size = 3;
printArray<int*, size>(testarray); 传入会报错 */
}
int main()
{
testFunc();
}
/*输出*/
123
123