怎么把网站列入黑名单wordpress 酒主题
news/
2025/10/8 11:38:17/
文章来源:
怎么把网站列入黑名单,wordpress 酒主题,松江 网站建设公司,永久免费浏览网页软件目录 一.泛型编程
二.函数模板
1.函数模板概念
2.函数模板格式
3.函数模板的原理
三.函数模板的实例化
1.隐式实例化
2.显式实例化
3.模板参数的匹配原则
四.类模板
1.类模板的定义格式
2.类模板的实例化 一.泛型编程
泛型编程#xff1a;编写与类型无关的通用代码…目录 一.泛型编程
二.函数模板
1.函数模板概念
2.函数模板格式
3.函数模板的原理
三.函数模板的实例化
1.隐式实例化
2.显式实例化
3.模板参数的匹配原则
四.类模板
1.类模板的定义格式
2.类模板的实例化 一.泛型编程
泛型编程编写与类型无关的通用代码是代码复用的一种手段。
泛型编程是一种编程范式它允许程序员编写不依赖于特定数据类型的代码。
在泛型编程中程序员可以定义一些通用的算法和数据结构这些可以在不同的数据类型中使用。
比如交换函数如果我们没有学习泛型编程则我们就需要根据类型的交换造出多个轮子
typedef int Type;
void Swap(Type left, Type right)
{Type temp left;left right;right temp;}void Swap(int left, int right)
{int temp left;left right;right temp;
}void Swap(double left, double right)
{double temp left;left right;right temp;
}使用函数重载固然可以实现这一问题但是有几个不好的地方 代码空间会变大重载的函数只是类型不同代码的复用率较低只要有新的类型需要使用这个函数就需要重载新的函数代码的可维护性较低一个出错可能全部的重载都出错
因为函数重载存在上述缺点因此我们提出了”函数模板“
在现实生活中我们可以通过往模具中填充不同的材料生成不同的铸件。
C的开发者受到了启发发明了模板。
模板告诉编译器一个模子让编译器根据不同的类型利用该模子生成代码。
模板可以分为函数模板和类模板 模板是泛型编程的基础。
二.函数模板
1.函数模板概念
函数模板代表了一个函数家族该家族模板与类型无关。
函数模板在使用时被参数化根据实参类型产生的特定类型版本。
2.函数模板格式
我们用templata关键字来声明模板
template typename T1, typename T2,......typename Tn
返回值类型 函数名(参数列表)
{//函数体
}
这里需要大家注意的是我们的第一行后面并没有分号也就代表着它并不是一条语句。 现在我们举出一个实例
template typename T//函数模板的声明
void Swap(T left, T right)
{T temp left;left right;right temp;
}
此外我们也可以使用class取代typename
template class T//函数模板的声明
void Swap(T left, T right)
{T temp left;left right;right temp;
} 现在我们使用一下我们定义的函数模板
#include iostream
using namespace std;
template class T//函数模板的声明
void Swap(T left, T right)
{T temp left;left right;right temp;
}
int main()
{int a 1, b 2;Swap(a, b);cout a b endl;double c 1.3, d 2.5;Swap(c, d);cout c d endl;return 0;
} 可以看到这里圆满的完成了交换逻辑。
3.函数模板的原理
那么上述问题是如何解决的呢
大家都知道瓦特改良蒸汽机人类开始了工业革命解放了生产力。
机器生产淘汰掉了很多手工产品。
本质是什么重复的工作交给了机器去完成。
因此有人给出了论调懒人创造世界。
函数模板的本质也是如此
现在我们进入汇编来看一下上述代码运行的过程中编译器都干了什么事 可以看到这里调用函数时显式的规定了参数的类型。
因此我们可以得到结论函数模板是一个蓝图它本身并不是函数是编译器用使用方式产生特定具体类型函数的模具。
我们的编译器根据这个模具帮我们做了这个事情。 注意Swap在调用时调用的不是void Swap(T left, T right)而是编译器预先根据要调用的类型进行推演。 编译器负责在编译时分析模板定义并在需要时生成特定类型的代码之后编译器会检查模板的语法并确保模板的使用是合法的之后编译器会根据实际使用的类型参数生成相应的函数或类的实现。 例如上图中的这两行代码
00007FF6E7122423 call Swapint (07FF6E7121352h)
00007FF6E7122480 call Swapdouble (07FF6E7121398h)
这两个函数模板就是编译器生成的。 在编译器的编译阶段编译器就会根据传入的实参类型来推演生成对应类型的函数以供调用。
就比如上图 当用double类型使用函数模板时编译器通过对实参类型的推演将T确定为double类型然后产生一份专门处理double类型的代码。
三.函数模板的实例化
用不同类型的参数使用函数模板称为函数模板的实例化。
模板参数的实例化可以分为隐式实例化和显式实例化。
1.隐式实例化
隐式实例化即我们刚刚实例化的方法这里不再过多赘述。
#include iostream
using namespace std;
template class T//函数模板的声明
T Add(const T left, const T right)
{return left right;
}
int main()
{int a1 10, a2 20;Add(a1, a2);cout Add(a1,a2) endl;return 0;
} 现在我们来看一下这段代码
T Add(const T left, const T right)
{return left right;
}
int main()
{int a1 10, a2 20;double d1 10.1, d2 20.2;Add(a1, d2);cout Add(a1, d2) endl;return 0;
}
这段代码在大部分编译器下是无法运行的在VS2022中爆出了如下警告 为什么在大部分编译器下无法通过编译呢
这是因为在编译期间当编译器看到该实例化后会去推演其实参的类型。
但通过实参a1将T推演为了int通过实参d1将T推演为double类型。
但是模板参数列表中只有一个T编译器就无法判断T在这里是int还是double。
为什么在vs2022中可以编译成功呢
这是因为编译器进行了类型转换操作但是类型转换操作的风险是极大的因为不知道此处你想要的是double还是int。
那么我们应该处理这个问题呢
处理方式1用户自己强制转换
Add(a1, (int)d2);//想要int类型的我们直接将d2强转为int处理方式2采用显式实例化
那么如何显式实例化呢
2.显式实例化
显式实例化在函数名的后面参数列表的前面加一对尖括号尖括号内部指定模板参数的实际类型。如下
Addint(a, b);如果参数类型不匹配编译器会尝试进行隐式类型转换如果无法转换成功编译器将会报错。
3.模板参数的匹配原则
在我们的程序中一个非模板函数是可以和一个同名的函数模板同时存在的而且该函数模板还可以被实例化为这个非模板函数
T Add(const T left, const T right)
{cout T Add(T left,T right) endl;return left right;
}
int Add(const int left, const int right)
{cout int Add(int left, int right) endl;return left right;
}
int main()
{Add(1, 2);Addint(1, 2);return 0;
}
我们运行之后可以看到如下的结果 我们发现第一个Add函数调用了专门处理int类型的加法函数而第二个Add函数调用了模板。
那么为什么第一个Add函数不调用函数模板呢
这是因为如下内容
对于非模板函数和同名函数模板如果其他条件都相同在调用时会优先调用非模板函数而不会从该模板产生出一个实例。 如果条件不同的话则会选择模板。也就是说编译器会优先调用更加匹配的版本调用
我们可以看一下下面的这段代码
int Add(int left, int right)
{cout int Add(int left, int right) endl;return left right;
}
// 通用加法函数
templateclass T1, class T2//注意这里有两个类型
T1 Add(T1 left, T2 right)
{cout T1 Add(T1 left, T2 right) endl;return left right;
}
int main()
{Add(1, 2);// 与非函数模板类型完全匹配不需要函数模板实例化Add(1, 2.0);// 模板函数可以生成更加匹配的版本编译器根据实参生成更加匹配的Add函数return 0;
} 可以看到第一个调用了非模板函数第二个调用了模板函数。 模板函数不允许自动类型转换但普通函数可以进行自动类型转换。
对于模版T1 Add(T1 left, T2 right)不知道返回值是T1或T2可以选择autoauto虽然不太适合做返回值但是对于简单普通函数操作可以进行自动类型转换。
int Add(int left, int right)
{cout int Add(int left, int right) endl;return left right;
}//auto可作简单处理的函数返回值
templateclass T1, class T2
auto Add(const T1 left, const T2 right)
{cout auto Add(const T1 left, const T2 right) endl;return left right;
}
int main()
{Add(1, 2);// 与非函数模板类型完全匹配不需要函数模板实例化cout Add(1, 2) endl;Add(1, 2.0);// 模板函数可以生成更加匹配的版本编译器根据实参生成更加匹配的Add函数cout Add(1, 2.0) endl;return 0;
} 四.类模板
1.类模板的定义格式
templateclass T1, class T2, ..., class Tn
class 类模板名
{// 类内成员定义
};// 动态顺序表
// 注意Vector不是具体的类是编译器根据被实例化的类型生成具体类的模具
templateclass T
class Vector
{
public:Vector(size_t capacity 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}~Vector();//类外定义void PushBack(const T data)void PopBack()// ...size_t Size() { return _size; }T operator[](size_t pos){assert(pos _size);return _pData[pos];}
private:T* _pData;size_t _size;size_t _capacity;
};
// 注意类模板中函数放在类外进行定义时需要加模板参数列表
template class T
VectorT::~Vector()
{if (_pData)delete[] _pData;_size _capacity 0;
}
模版Vector中只是提供了一个模具具体印刷出什么模型是由编译器最终实例化决定的。
注意模版不建议声明和定义分离到.h 和.cpp会出现链接错误要分离也分离在.h。
2.类模板的实例化
类模板实例化与函数模板实例化不同类模板实例化需要在类模板名字和变量名字中间加一个尖括号然后将实例化的类型放在中即可类模板名字不是真正的类而实例化的结果才是真正的类。
Vectorint intvector;
Vectorstring stringvector; 码字不易如果你觉得博主写的不错的话可以关注一下博主哦。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/931451.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!