C++中提供两种模板机制:函数模板和类模板
函数模板
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表;
template<typename T>
函数声明或定义
//函数模板
template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型;
void MySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
void test02()
{
//利用函数模板来交换
//两种方式使用函数模板
//1、自动类型推导
int a = 1, b = 2;
MySwap(a, b);
cout << a << " " << b << endl;
//2、显示指定类型
double c = 1.1, d = 2.2;
MySwap<double>(c, d);
cout << c << " " << d << endl;
}
注意事项:
自动类型推导,必须推导出一致的数据类型T,才可以使用
模板必须要确定出T的数据类型,才可以使用
普通函数和函数模板
区别
-
普通函数调用时可以发送自动类型转换(隐式类型转换)
-
函数模板调用时,如果利用自动类型推导,不会发送隐式类型转换
-
如果利用显示指定类型的方式,可以发送隐式类型转换
//普通函数
int add01(int a, int b)
{
return a + b;
}template<class T>
T add02(T a, T b)
{
return a + b;
}void test03()
{
int a = 10;
int b = 20;
char c = 'a';//a -->97
cout << add01(a, b) << endl;
cout << add01(a, c) << endl;//1、自动类型推导 cout << add02(a, b) << endl; //cout << add02(a, c) << endl;//报错 //2、显示指定类型 cout << add02<int>(a, c) << endl;
}
规则
-
如果函数模板和普通函数都可以实现,优先调用普通函数
-
可以通过空模板参数列表来强制调用函数模板
-
函数模板也可以发生重载
-
如果函数模板可以产生更好的匹配,优先调用函数模板
add02<>(a,b):强制调用
template<class T>void Print(T a, T b)
{
cout<<"调用模板"<<endl;
}
template<class T>
void Print(T a, T b,T c)
{
cout<<"重载模板"<<endl;
}
局限性
模板不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
class Person
{
public:
Person(string name,int age)
{
_name = name;
_age = age;
}
public:
string _name;
int _age;
};
//对比两个数据是否相等
template<class T>
bool myCompare(T& a, T& b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//利用具体话Person版本实现代码,具体化优先调用
template<> bool myCompare(Person &p1, Person& p2)
{
if (p1._name == p2._name && p1._age == p2._age)
{
return true;
}
return false;
}
void test04()
{
int a = 10;
int b = 20;
bool ret = myCompare(a, b);
cout << ret << endl;
Person p1("Tom", 10);
Person p2("Tom", 10);
ret = myCompare(p1, p2);
cout << ret << endl;
}
类模板
//类模板
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
_name = name;
_age = age;
}
public:
NameType _name;
AgeType _age;
};
void test01()
{
Person<string, int> p1("Tom", 9);
}
类模板和函数模板区别
- 类模板没有自动类型推导的使用方式
//Person p1("Tom", 9); 错误,无法使用自动类型推导
Person<string, int> p1("Tom", 9); //正确,只能用显示指定类型
- 类模板在模板参数列表中可以有默认参数
template<class NameType,class AgeType = int>
Person<string> p1("Tom", 9);
类模板中成员函数创建时机
-
普通类中的成员函数一开始就可以创建
-
类模板中的成员函数在调用时才创建
类模板对象做函数参数
三种传入方式:
-
指定传入类型 --直接显示对象的数据类型
-
参数模板化 --将对象中的参数变为模板进行传递
-
整个类模板化 --将这个对象类型模板化进行传递
//类模板对象做函数参数
template<class T1,class T2>
class Person
{
public:
Person(T1 name, T2 age)
{
_name = name;
_age = age;
}
void show()
{
cout << "姓名:" << _name << ", 年龄:" << _age << endl;
}
public:
T1 _name;
T2 _age;
};
//1、指定传入类型
void printPerson1(Person<string, int> &p)
{
p.show();
}
void test02()
{
Person<string, int> p1("Tom", 20);
printPerson1(p1);
}
//2、参数模板化
template<class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{
p.show();
cout <<"T1的类型为:" << typeid(T1).name() << endl;
cout <<"T1的类型为:" << typeid(T2).name() << endl;
}
void test03()
{
Person<string, int> p1("Tom", 20);
printPerson2(p1);
}
//3、整个类模板化
template<class T>
void printPerson3( T &p)
{
p.show();
cout << "T的数据类型为:" << typeid(T).name() << endl;
}
void test04()
{
Person<string, int> p1("Tom", 20);
printPerson3(p1);
}
类模板与继承
//类模板与继承
template<class T>
class Base
{
T m;
};
class Son :public Base<int>//必须要知道父类中的T类型,才能继承给子类
{
};
//如果想灵活指定父类中的T类型,子类也需要变成类模板
template<class T1,class T2>
class Son2 :public Base<T1>
{
T2 obj;
};
void test05()
{
Son2<int, char> s2;
}
类模板成员函数的类外实现
//类模板成员函数的类外实现
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void show();
public:
T1 _name;
T2 _age;
};
template<class T1,class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->_name = name;
this->_age = age;
}
template<class T1, class T2>
void Person<T1, T2>::show()
{
cout << "姓名:" << _name << ", 年龄:" << _age << endl;
}
void test05()
{
Person<string, int> p("Tom", 20);
p.show();
}
类模板的分文件编写
就是声明在.h文件,实现在.cpp中实现:
报错原因:
类模板中成员函数创建时间是在调用的时候才会创建;所以链接.h文件的时候,并不会生成成员函数,所以在调用的时候就会报错,找不到这个成员函数
解决方法:
-
直接包含.cpp源文件
-
将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制的
类模板与友元
全局函数类内实现-直接在类内声明友元即可
全局函数类外实现-需要提前让编译器知道全局函数的存在
//提前让编译器知道Person类的存在
template<class T1, class T2>
class Person;
//类外实现
template<class T1, class T2>
void show2(Person<T1, T2>p)
{
cout << "姓名:" << p._name << ", 年龄:" << p._age << endl;
}
template<class T1,class T2>
class Person
{
//全局函数,类内实现
friend void show1(Person<T1,T2>p)
{
cout << "姓名:" << p._name << ", 年龄:" << p._age << endl;
}
//全局函数,类外实现
//加空模板参数列表
friend void show2<>(Person<T1, T2>p);
public:
Person(T1 name, T2 age)
{
_name = name;
_age = age;
}
public:
T1 _name;
T2 _age;
};
void test06()
{
Person<string, int>p("Tom", 20);
show1(p);
Person<string, int>p1("Jorry", 20);
show2(p1);
}