函数模板
语法
template
template 声明创建模板
typename 表明其后面的符号是一种数据类型 可以用class替换
T 通用的数据类型 名称可以替换
template<typename T>
void swap(T &a,T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
使用方法
1.自动类型推导
就是直接用这个函数 让编译器自己去推断 不允许隐式转换
2.显式指定类型
可以隐式转换
swap(a,b);
调用规则
1.如果函数模板和普通函数都可以实现 优先调用普通函数
2.可以通过空模板参数列表强制调用函数模板
例如swap<>(a,b) 就是强制调用函数模板了
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配 优先调用函数模板
也就是如果你的普通函数参数类型int类型 而你传进去的参数是char类型 这时普通函数虽然可以发生隐式转换 但是如果有模板在的情况下 优先调模板
typename
ypename 的作用就是告诉 c++ 编译器,typename 后面的字符串为一个类型名称,而不是成员函数或者成员变量
模板具体化
template<> bool myCompare(Person &a,Person &b)
当参数可能是自定义结构体或者类时 可能出现无法匹配参数的问题
例如:
class Person
{
public:
int age;
string name;
}
/此时如果调用这个模板肯定是不匹配的/
templatebool myCompare(T &a,T &b)
{
if(a = = b)
return ture;
else
return false;
}
/函数模板具体化/ //这样就行了
template<> bool myCompare(Person &a,Person &b)
{
if(a.age = = b.age)
return ture;
else
return false;
}
例子
template<typename T>
void swap(T &a,T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
int main()
{
int a = 1;
int b = 2;
char c = 'c';
swap(a,b);//自动类型推导
swap<int>(a,b);//显示指定类型 不允许隐式转换
swap<int>(a,c);//这样也是可以运行的 显示指定类型可以发生隐式转换 就是把char类型转换成int类型(c的ascll码)
}
类模板
语法
template
类
注意
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数、
template<typename T,typename B = int>//默认参数类型
3.类模板中成员函数在调用时才去创建(普通类成员函数一开始就创建)
class person1
{
void show();
};
template<typename T>
class person2
{
public:
T obj;
void func()
{
//这样在创建person2对象前 他是不会报错的
//就算根本不存在get()函数 因为系统目前并不知道
//T目前是什么类型
T.show();
T.get();
}
};
类模板对象做函数参数
三种传入方式:
指定传入类型
void printPerson1(Person<string ,int>&p)
{
p.showPerson();
}
int main()
{
Person<string,int>p("孙悟空",100);
printPerson1(p);
}
参数模板化
templatr<class T1,class T2>
void printPerson1(Person<T1,T2>&p)
{
p.showPerson();
cout<<typeid(T1).name();//可以显示T1的数据类型
}
int main()
{
Person<string,int>p("孙悟空",100);
printPerson1(p);
}
整个类模板化
templatr<class T1>
void printPerson1(T1 &p)
{
p.showPerson();
}
int main()
{
Person<string,int>p("孙悟空",100);
printPerson1(p);
}
指定传入的类型
直接显示对象的数据类型
参数模板化
将对象中的参数变为模板进行传递
整个类模板化
将这个对象类型模板化进行传递
例子
template<typename T,typename B = int>//默认参数类型 这样在下面构造的时候
//Person<string> p1("孙悟空",999);就可以不用int了
template<typename T,typename B>
class Person
{
public:
T name;
B age;
Person(T name,B age)
{
this->name = name;
this->age = age;
}
};
int main()
{
Person<string,int> p1("孙悟空",999);
Person p1("孙悟空",999);//这是不行的
}
类模板的继承
注意
1.当子类继承的父类是一个类模板时 子类在声明的时候要指定出父类中的类型
2.如果不指定编译器不发给子类分配内存
例子
template<class T>
class Base
{
T age;
}
//指定子类的类型
class Son:public Base<int>
{
}
//将子类也变成模板
template<class T1,class T2>
class Son2 :public Base<T2>
{
T1 obj;
}
类模板类外实现
template<class T1,class T2>
class Person
{
public:
T1 age;
T2 name;
Person(T1 age,T2 name);
void show();
}
template<class T1,class T2>
Person<T1,T2>::Person(T1 age,T2 name)
{
this->age = age;
this->name = name;
}
template<class T1,class T2>
void Person<T1,T2>::show()//就算没有参数 也要写<T1,T2>体现是一个模板
{
}
类模板分文件编写 .hpp
第一种解决方法 直接#include".cpp"而不是#include".h"
如果头文件中有模板类 并且类模板中的成员函数定义是在cpp文件中实现 那么在另一个文件中调用这个类成员函数的时候就会出现无法解析的外部命令 因为类模板的成员函数是不会在开始的时候就创建的 类模板中成员函数在调用时才去创建 所以编译器根本无法见到cpp文件中的成员函数定义
第二种解决方法 将.h和.cpp内容写到一起 后缀名改为.hpp文件 约定熟成hpp就是类模板文件
类模板和函数模板的区别
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数