一.概况
1.什么是泛型编程呢?
在计算机程序设计领域,为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,人们发展的泛型及泛型编程技术。所以泛型,实质上就是不使用具体数据类型(例如 int、double、float 等),
而是使用一种通用类型来进行程序设计的方法,该方法可以大规模的减少程序代码的编写量,让程序员可以集中精力用于业务逻辑的实现。
2.C++模板
是一种用于创建通用代码的机制,它允许程序员编写适用于多种数据类型的通用函数或类。
模板的定义和实现通常分为两部分:头文件(.h或.hpp文件)中的模板声明和实现文件(.cpp文件)中的模板定义。
3.C++模板的优点主要包括
灵活性、可重用性和可扩展性:模板可以使得同一个算法适用于不同类型的数据,提高了代码的复用性。
减少开发时间:通过模板,程序员可以避免为每个数据类型单独编写相似的代码,从而提高了开发效率。
高效性:相较于C++类继承实现多态,模板模拟多态的效率更高,因为它避免了虚函数和继承的开销。
C++模板也存在一些缺点:
易读性和调试性较差:模板的代码相对于普通代码来说更为复杂,可能导致代码可读性降低,同时调试起来也可能更为困难。
数据类型在编译时确定:模板的数据类型必须在编译时才能被确定,这在一定程度上限制了模板的灵活性。
编译时间长:当工程较大时,所有基于模板算法的实现都必须包含在整个设计的头文件中,这可能导致编译时间较长。
总的来说,C++模板是一种强大的工具,可以极大地提高代码的可重用性和效率,但在使用时也需要注意其可能带来的问题。
二.函数模板
1.定义
函数模板实际上是定义一个通用函数,它所用到的数据的类型(包括返回值类 型、形参类型、局部变量类型)均被作为参数:不指定具体类型,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位)。
凡是函数体相同的函数都可以用这个模板来代替,在函数调用时根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板。
2.函数模板的格式
template <typename 形参名, typename 形参名...> //模板头(模板说明)
返回值类型 函数名(参数列表) //函数定义
{
函数体;
}
注意:
template是声明模板的关键字,告诉编译器开始泛型编程。
尖括号<>中的typename是定义形参的关键字,用来说明其后的形参名为类型参数(模板形参)。Typename可以用class关键字代替,两者没有区别。
模板形参不能为空(俗成约定用一个大写英文字母表示),且在函 数定义部分的参数列表中至少出现一次。与函数形参类似,可以用在函数定义的各个位置:返回值、形参列表和函数体。
函数定义部分:与普通函数定义方式相同,只是参数列表中的数据类型要使用尖括号<>中的模板形参名来说明。当然也可以使用一般的类型参数。
3.示例
用函数模板实现多种类型数据的相加
#include <iostream>
using namespace std;
template<typename T>//模板头,template关键字告诉编译器开始泛型编程
T add(T t1, T t2)//类型参数化为T
{
return t1 + t2;
}
int main()
{
cout << add(12, 34) << endl;
cout << add(12.2,45.6) << endl;
return 0;
}
输出结果:
46
57.8
4.函数模板的实例化
函数模板实例化的方法有两种:
隐式实例化:根据具体的函数调用形式,推演出模板参数类型。
显式实例化:通过显式声明形式指定模板参数类型
(1)隐式实例化
根据函数调用时传入的数据类型,推演出模板形参类型。模板形参的类型是隐 式确定的。
比如上面的多种类型相加
第一次调用add()函数模板:add(12,34),
①编译器根据传入的实参(12和34—>int型),推演出模板形参类型是int
②会将函数模板实例化出一个int类型的函数:
int add(int t1, int t2)
{
return t1 + t2;
}
③生成int类型的函数后,再将实参12和34传入进行运算。
第二次调用add()函数模板:add(12.2, 45.6)
实参为float类型的数据,编译器先将模板实例化为如下模板函数后,再将实 参12.2和45.6传入进行运算:
float add(float t1, float t2)
{
return t1 + t2;
}
(2)显式实例化
调用的时候显式实例化函数:
qDebug()<< add<int>(10,12.4);
输出:22 //输入的参数12.4会自动转换为int类型
5.函数模板的重载
函数模板可以用来创建一个通用功能的函数,以支持多种不同形参,不同类型的参数调用,就产生一系列重载函数。
比如定义一个两个数相加的模板
根据传入参数不同,会实例化出不同的函数,比如
template<typename T>
T add(T t1, T t2)
{
return t1 + t2;
}
三.类模板
1.定义类模板的格式
template<typename 形参名,typename 形参名…>
class 类名
{
………
}
说明:
(1)类模板中的关键字含义与函数模板相同。
(2)类模板中的类型参数可用在类声明和类实现中。类模板的模板形参(类型参数)不能为空,一旦声明了类模板就可以用类模板的形参名声明类中的成员变量和成员函数,即在类中使用内置数据类型的地方都可以使用模板形参名来代替。
test.h: 定义
template<typename T>
class classA
{
public:
T a; //成员变量
T b; //成员变量
T add(T a, T b) //成员函数声明
{
return a + b;
}
};
test.cpp: 应用
classA<int> iCA;
qDebug()<<"result:"<<iCA.add(7,16.3);
输出:23 //参数b输入16.3会自动转化为int类型
2.类模板的实例化
定义了类模板后就要使用类模板创建对象以及实现类中的成员函数,这个过程其实 也是类模板实例化的过程,实例化出的具体类称为模板类。
(1)使用类模板创建对象时,必须指明具体的数据类型。
例如:用上述定义的模板类A创建对象,则在类A后面跟<>,并在里面表明相应 的类型:
A<int> a; //类A中凡是用到模板形参的地方都会被int类型所代替
(2)当类模板有两个模板形参时,创建对象时,类型之间要用逗号分隔开。
(3)可以使用对象指针的方式来实例化