模板
模板是一类通用的模型,无论什么情况我们都有可以调用他,提高复用性。
C++中的模板分为函数模板和类模板两大类型。
函数模板
作用:建立一个通用的函数,其函数返回值类型和形参不具体指向特定的数据类型,用一个虚拟的类型来表示
语法:
template<typename T>
函数声明
很容易template表示这是一个模板,typename后面的T是一个数据类型,可以用class代替。T就是一个变量
在使用过程中可以系统可以自己推导出来数据类型且必须一致才可以使用,同时也可以自己指定数据类型。
//模板-1
#include<iostream>
using namespace std;
//利用模板提供通用的交换函数
template<class T>
void mySwap(T& a, T& b)
{
cout<<"mySwap的调用"<<endl;
T temp = a;
a = b;
b = temp;
}
// 1、自动类型推导,必须推导出一致的数据类型T,才可以使用
void test01()
{
int a = 10;
int b = 20;
char c = 'c';
c++;
mySwap(a, b); // 正确,可以推导出一致的T
//mySwap(a, c); // 错误,推导不出一致的T类型
}
// 2、模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{
cout << "func 调用" << endl;
}
void test02()
{
//func(); //错误,模板不能独立使用,必须确定出T的类型
func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}
int main() {
test01();
test02();
return 0;
}
结果:
mySwap的调用
func 调用
不过函数模板并不是万能的,还是有它的局限性的。C++还可以对模板重载和对特定的数据类型进行具体化。
譬如说:
//具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
template<> bool myCompare(Person &p1, Person &p2)
上面就是一个简单的例子,他对bool类型进行了一个特殊的定义。
类模板
语法同函数模板,类模板没有自动类型推导的使用方式也就是说,你必须使用指定类型
例如:
Peson<string,int>p("刘纪彤",1000);
值得一提的是类模板中的模板参数列表可以有默认参数。
template<class NameType, class AgeType = int>
像这样AgeType就默认是int,后面可以直接用默认的int类型。大体和函数那里互相类似。
类模板中的成员函数并不是一开始就创建的,在调用时才去创建
//模板-2
#include<iostream>
using namespace std;
class Person1
{
public:
void showPerson1()
{
cout << "Person1 show" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "Person2 show" << endl;
}
};
template<class T>
class MyClass
{
public:
T obj;
//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成
void fun1() { obj.showPerson1(); }
void fun2() { obj.showPerson2(); }
};
void test01()
{
MyClass<Person1> m;
m.fun1();
//m.fun2();//error: 'class Person1' has no member named 'showPerson2';
}
int main()
{
test01();
return 0;
}
结果:
Person1 show
传参数的时候可以有三种情况一共有三种传入方式:
- 指定传入的类型 --- 直接显示对象的数据类型
- 参数模板化 --- 将对象中的参数变为模板进行传递
- 整个类模板化 --- 将这个对象类型 模板化进行传递
//1、指定传入的类型
void printPerson1(Person<string, int> &p)
//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
//3、整个类模板化
template<class T>
void printPerson3(T & p)
模板的继承:
当类模板碰到继承时,需要注意一下几点:
- 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也需变为类模板
示例
class Son :public Base<int> //必须指定一个类型
//类模板继承类模板 ,可以用T2指定父类中的T类型
template<class T1, class T2>
class Son2 :public Base<T2>
类外实现就可以用通过::实现,示例代码如下:
template<class T1, class T2>
void Person<T1, T2>::showPerson() {}
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {}
类模板实现友元函数:
全局函数类内实现 - 直接在类内声明友元即可
全局函数类外实现 - 需要提前让编译器知道全局函数的存在