旅游网站开发的流程,网站建设概,页面模板微信,泸州建设局网站目录
C泛型编程思想
C模版
模版介绍
模版使用
函数模版
函数模版基础语法
函数模版原理
函数模版实例化
模版参数匹配规则
类模版
类模版基础语法 C泛型编程思想
泛型编程#xff1a;编写与类型无关的通用代码#xff0c;是代码复用的一种手段。
模板是泛型编程…目录
C泛型编程思想
C模版
模版介绍
模版使用
函数模版
函数模版基础语法
函数模版原理
函数模版实例化
模版参数匹配规则
类模版
类模版基础语法 C泛型编程思想
泛型编程编写与类型无关的通用代码是代码复用的一种手段。
模板是泛型编程的基础。
虽然可以直接使用函数重载来解决不同类型的问题但是使用函数重载会出现可能不好的地方
重载的函数仅仅是类型不同代码复用率比较低只要有新类型出现时就需要用户自己增加对应的函数代码的可维护性比较低一个出错可能所有的重载均出错
C模版
模版介绍
在C语言中当需要交换两个变量的数据时需要考虑到不同类型例如下面的代码
#define _CRT_SECURE_NO_WARNINGS 1#include stdio.h//交换int类型数据
void swap_int(int* num1, int* num2)
{int tmp *num1;*num1 *num2;*num2 tmp;
}//交换double类型的数据
void swap_double(double* num1, double* num2)
{double tmp *num1;*num1 *num2;*num2 tmp;
}int main()
{int num1 1, num2 2;printf(num1%d num2%d\n, num1, num2);swap_int(num1, num2);printf(num1%d num2%d\n, num1, num2);double num3 4.1, num4 4.5;printf(num3%.1f num4%.1f\n, num3, num4);swap_double(num3, num4);printf(num3%.1f num4%.1f\n, num3, num4);return 0;
}
输出结果
num11 num22
num12 num21
num34.1 num44.5
num34.5 num44.1
在上面的C语言代码中当需要交换int类型的数据时需要int类型交换函数需要double类型的数据时需要double类型的交换函数但是这两个函数除了类型不同以外其他代码都一样增加了工作量并且因为C语言不支持函数重载所以两个交换函数的函数名不能相同
为了解决上面的问题C中提出了一种模版函数如下面代码
#include iostream
using namespace std;templateclass T
void Swap(T num1, T num2)
{T tmp num1;num1 num2;num2 tmp;
}int main()
{int num1 1, num2 2;printf(num1%d num2%d\n, num1, num2);Swap(num1, num2);printf(num1%d num2%d\n, num1, num2);double num3 4.1, num4 4.5;printf(num3%.1f num4%.1f\n, num3, num4);Swap(num3, num4);printf(num3%.1f num4%.1f\n, num3, num4);return 0;
}
输出结果
num11 num22
num12 num21
num34.1 num44.5
num34.5 num44.1
在上面的代码中将Swap函数作为一种模版当调用Swap函数时根据传入的参数类型自动实例化函数从而完成函数执行
模版使用
函数模版
函数模版基础语法
templatetypename name1, typename name2, ...
函数返回类型 函数名(形式参数)
{//函数体
}//typename也可以用class代替但是不可以用struct
在C中使用template关键字创建模版使用包裹函数体中需要使用到类型typename name1用于指代的类型在函数调用时自动匹配类型默认不会隐式类型转换模版下方正常写函数即可 模版函数的下方也可以写其他普通函数
#include iostream
using namespace std;//模版
templateclass T
void Swap(T num1, T num2)
{T tmp num1;num1 num2;num2 tmp;
}//普通函数
int add(const int num1, const int num2)
{return num1 num2;
}int main()
{int num1 1, num2 2;printf(num1%d num2%d\n, num1, num2);Swap(num1, num2);printf(num1%d num2%d\n, num1, num2);double num3 4.1, num4 4.5;printf(num3%.1f num4%.1f\n, num3, num4);Swap(num3, num4);printf(num3%.1f num4%.1f\n, num3, num4);cout add(num1, num2) endl;//可以正常使用return 0;
}
输出结果
num11 num22
num12 num21
num34.1 num44.5
num34.5 num44.1
3
函数模版原理
函数模板是一个蓝图它本身并不是函数是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
在函数调用的过程中直接调试时不论是int类型还是double类型都会走到模版但是进入反汇编可以看到当形参是int类型时编译器会进入int类型的函数同样double类型类似 所以函数模版是告诉编译器应该生成何种类型的函数如下图所示 在编译器编译阶段对于模板函数的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用
函数模版实例化
用不同类型的参数使用函数模板时称为函数模板的实例化。
模板参数实例化分为隐式实例化和显式实例化
隐式实例化让编译器根据实参类型自动推演出形式参数类型
#include iostream
using namespace std;templateclass T
void Swap(T num1, T num2)
{T tmp num1;num1 num2;num2 tmp;
}int main()
{int num1 1, num2 2;printf(num1%d num2%d\n, num1, num2);Swap(num1, num2);//自动推演出int类型printf(num1%d num2%d\n, num1, num2);return 0;
}
输出结果
num11 num22
num12 num21
但是当模版参数类型种类个数与实参种类个数不匹配时编译器将无法自动推演
#include iostream
using namespace std;templateclass T
void add(T num1, T num2)
{return num1 num2;
}int main()
{int num1 1;double num2 2.0;add(num1, num2);//无法自动推演return 0;
}
报错信息
没有与参数列表匹配的 函数模板 Swap 实例
在上面的代码中函数模版中只有一种类型但是实际调用函数传递的实际参数对应两种类型此时因为类型不对应编译报错
第一种解决方式添加额外种类的模版参数
#include iostream
using namespace std;templateclass T, class R
T add(T num1, R num2)
{return num1 num2;
}int main()
{int num1 1;double num2 2.0;cout add(num1, num2) endl;//当函数模版有两种参数时可以自动推演return 0;
}
输出结果
3
在上面的代码中类型T被推演为int类型R被推演为double但是有个返回值问题因为函数返回值只能为一种所以存在精度丢失
第二种解决方式对某一种类型进行强制转换
以强制转换int类型为例
#include iostream
using namespace std;templateclass T
T add(T num1, T num2)
{return num1 num2;
}int main()
{int num1 1;double num2 2.2;cout add((double)num1, num2); endl;//将int类型转换为double类型return 0;
}
输出结果
3.2
第三种解决方式显式实例化
#include iostream
using namespace std;templateclass T
T add(T num1, T num2)
{return num1 num2;
}int main()
{int num1 1;double num2 2.2;cout adddouble(num1, num2) endl;//强制指定T为double类型此时会隐式转换return 0;
}
输出结果
3.2
对于显式实例化来说如果此时类型依旧不匹配编译器会尝试进行隐式类型转换如果无法转换成功编译器将会报错 注意第二种方式和第三种方式都有强制性指定的类型时何种类型函数模版就一定是何种类型哪怕函数模版的形参是同类型的引用编译器也无法识别
模版参数匹配规则
一个非模板函数可以和一个同名的函数模板同时存在而且该函数模板还可以被实例化为这个非模板函数对于非模板函数和同名函数模板如果其他条件都相同在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数 那么将选择模板
#include iostream
using namespace std;
//同名函数模版和非模版函数
//函数模版
templateclass T, class R
R add(T num1, R num2)
{return num1 num2;
}//单独处理整型加法
int add(int num1, int num2)
{return num1 num2;
}int main()
{int num1 1;int num2 2;cout add(num1, num2) endl;//此时编译器会调用单独处理整型加法的函数而不是根据函数模版推演出新的int形参函数double num3 2.2;cout add(num1, num3) endl;//编译器直接推演出不需要强制转换的函数return 0;
}
输出结果
3
3.2
类模版
类模版基础语法
templatetypename name1, typename name2
class 类名
{//类体
};
在C中使用template关键字创建模版使用包裹类体体中需要使用到的类型typename name1用于指代类型在使用类时自动匹配数据类型默认不会隐式类型转换模版下方正常写类即可 注意使用模版类创建类对象时必须显式指定类型
#include iostream
using namespace std;templateclass T
class SeqList
{
private:T* _a;int _size;int _capacity 4;
public:SeqList():_a(nullptr){_a new T[_capacity];}~SeqList(){delete[] _a;_size _capacity 0;}
};int main()
{//类模版必须显式制定类型SeqListint s1;//存放int类型数据的顺序表SeqListdouble s2;//存放double类型的顺序表return 0;
} 类模板实例化与函数模板实例化不同类模板实例化需要在类模板名字后跟然后将实例化的类型放在中即可类模板名字不是真正的类而实例化的结果才是真正的类
例如上面的代码中有两个类一个是SeqListint一个是SeqListdouble
如果声明和定义分开时域作用限定符左侧的域名一定要带上模版参数列表
SeqListint::~SeqList()
{delete[] _a;_size _capacity 0;
}SeqListdouble::~SeqList()
{delete[] _a;_size _capacity 0;
}