模板的概念:
C++模板是一种强大的工具,允许程序员编写与类型无关的代码。这使得代码更加通用和灵活,从而可以在不同的数据类型上重用。就比如一个充电器,它可以为各种不同品牌和型号的手机、电池或其他设备充电,用的都是同一个接口。这个充电器的设计是通用的,能够适应不同设备的充电需求。
函数模板
函数模板概念:
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板格式:
template<typename T>
void Swap( T&x, T&y)
{
T temp = x;
x = y;
y = temp;
}
template<typename>是一个定义模板的语法,typename是用来定义模板参数关键字,也可以使用class但不允许使用struct。它允许创建一个泛型类或函数,这样可以在编写代码时指定特定的数据类型,而不需要为每种类型编写重复的代码。
template<typename T>这是一个模板声明,T是一个占位符,代表一个类型参数。这个参数在模板实例化时会被实际的类型所替代。
上图代码定义了一个名为Swap的函数模板,用于交换两个同类型变量的值,T&表示x和y 是类型T的引用。这个函数将交换传入的两个变量的值。
如果按照C语言的方式想交换两个不同类型的变量,那么分别需要定义两个类型不同的函数,而这两个函数仅仅至少类型不同其他参数都相同。那么可以看到上图代码,定义了四个变量,分别是int与double,只运用了一个模板函数Swap进行传参就完成了变量的交换。
函数模板原理:
从上图可以看到,模板仅仅至少充当一个中介的角色,当给模板传入实参,编译器会根据实参的类型去推演自动生成对应类型的函数,可以从下图的汇编码能更好的证明这一点
函数模板实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
隐式实例化:
让编译器根据传入的实参去自动推演模板参数的实际类型
如上图,编译器会根据传入的实参类型自动推演并生成相应的函数,这点在原理可以很清晰的知道。
可以看到上图代码,如果传入的实参类型不同,编译运行程序会发生报错。因为传入的类型一个是int,一个是double,会发生传类型不明确。就像假如你在家犯了个错,爸爸叫你面壁,你面壁了一会,妈妈叫你别面壁了去休息,但爸爸说不可以就继续面壁,此时就发生了混乱不知道该听谁的,
在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅。所以解决这种问题有两种方法,第一种:使用显示实例化(这点会在下面进行讲解),第二种强制类型转换。
显示实例化:
显式实例化:在函数名后的<>中指定模板参数的实际类型。
可以看到再Print模板后加上< 类型 >,编译器就知道需要传入的参数是什么类型就不会再纠结,如果是不同类型的化会发生隐式类型转换。
类模板
类模板格式:
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
template<class T>表示Stack类是一个模板类,可以看到将成员变量_arr的类型换成T模板类型,就可以根据传入不同类型生成不同类型的栈如 int,double ,甚至自定义类型.....。如果是C语言的话则会根据需求不同分别构建不同类型的栈结构,就会很麻烦。
类模板实例化
关于在类模板里声明函数,在类模板外定义的注意事项:
可以看到如果按照之前的方式仅仅通过访问限定符去定义类是完全不行的,在 C++ 中,模板类的成员函数定义必须指定模板参数,因为这些成员函数的定义是在模板类的上下文中进行的。