当前位置: 首页 > news >正文

宁波网站建设最好提供信息门户网站建设

宁波网站建设最好,提供信息门户网站建设,乐陵森林面积,地图截选做分析图的网站文章目录 一. 泛型编程二. 函数模板函数模板的原理函数模板的实例化隐式实例化: 让编译器根据实参推演模板参数的实际类型显示实例化: 在函数名后的<>中制定模板参数的世纪类型 模板参数的匹配原则 三. 类模板类模板的定义格式类模板的实例化 一. 泛型编程 如何实现一个…

文章目录

  • 一. 泛型编程
  • 二. 函数模板
    • 函数模板的原理
    • 函数模板的实例化
      • 隐式实例化: 让编译器根据实参推演模板参数的实际类型
      • 显示实例化: 在函数名后的<>中制定模板参数的世纪类型
    • 模板参数的匹配原则
  • 三. 类模板
    • 类模板的定义格式
    • 类模板的实例化

一. 泛型编程

如何实现一个通用的交换函数呢? 参数是不同类型的数据.

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;
}void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

使用函数重载虽然可以实现, 但是仍然有不足:

  1. 重载的函数仅仅是类型不同, 代码复用率比较低, 只要有新类型出现时, 就需要用户自己增加对应的函数
  2. 代码的可维护性比较低, 一个出错可能所有的重载均出错.

如果需要能在用户提供的类型上使用此函数, 这种策略就失效了.


那么, 能否告诉编译器一个模子, 让编译器根据不同的类型利用该模子来生成代码呢?

就像活字印刷术一样, 只要提供了字模, 就可以用不同的颜色来印出同样的字

在这里插入图片描述

C++提供了模板的语法, 给这个"模具"中填充不同的类型, 就可以生成具体类型的代码

泛型编程: 编写与类型无关的通用代码, 是代码复用的一种手段. 模板是泛型编程的基础.

在这里插入图片描述

二. 函数模板

针对上面 Swap 函数有多种类型参数的情况, 可以定义一个通用的函数模板(function template), 而不是为每个类型都定义一个新函数.

一个函数模板就是一个公式, 可用来生成针对特定类型的函数版本. Swap 的模板版本可能像下面这样:

template <typename T>     // 模板定义格式:  template<typename T1, typename T2, ... , typename Tn>
void Swap(T &left, T &right)
{T temp = left;left = right;right = temp;
}

模板定义以关键字 template 开始, 后面跟一个模板参数列表, 这是一个用逗号分割的一个或多个模板参数的列表, 用小于号 < 和 大于号 > 包围起来.

在模板定义中, 模板参数列表不能为空.

模板参数列表的作用很像函数参数列表.
函数参数列表定义了形参对象, 模板参数列表定义了类型.

模板参数表示类或函数定义中用到的类型或值. 当使用模板的时候, 显示或隐式地制定模板实参, 将其绑定到模板参数上.

比如上述的 Swap 函数声明了两个名为 T 的类型参数, T 表示一个类型, T 的实际类型则在编译时根据传入的参数确定.

对于不同的参数类型, 最终调用的函数参数类型也不同

在这里插入图片描述


函数模板的原理

函数模板是一个蓝图, 它本身并不是函数, 是编译器用使用方式产生特定具体类型函数的模具. 所以其实模板就是将本来应该我们做得重复的事情交给了编译器.

在这里插入图片描述

在编译器编译阶段, 对于函数模板的使用, 编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用.

例如: 当用 double 类型使用函数模板时, 编译器通过对实参类型的推演, 将 T 确定为 double 类型, 然后产生一份专门处理 double 类型的代码

注意 函数模板的模板参数类型可以写 typename, 也可以写 class (不可以写 struct).

函数模板的实例化

用不同类型的参数使用函数模板时, 称为函数模板的实例化.

在这里插入图片描述

隐式实例化: 让编译器根据实参推演模板参数的实际类型

template <typename T>
T Add(const T &left, const T &right)
{return left + right;
}int main()
{int a1 = 10, b1 = 20;Add(a1, b1);    // 推演出模板参数类型为 intdouble a2 = 1.1, b2 = 2.2;Add(a2, b2);    // 推演出模板参数类型为 doubleAdd(a1, b2);    // 推演失败return 0;
}

前两个可以通过编译, 函数模板类型相同, 编译器可以推演出函数模板的类型.

第三个传入了一个 int 类型和一个 double 类型, 编译器推演模板参数类型失败.

在这里插入图片描述

因为定义模板函数的时候, 规定了模板函数参数只有一个类型 T, 传入两个类型, 编译器不能确定应该是将 T 演绎成哪个类型.

在模板中, 编译器不会进行类型转换操作, 一旦转换出问题, 编译器就会背黑锅, 所以不会隐式转换.

有两种处理方式:

  1. 用户自己进行强化类型转换
  2. 使用显示实例化
Add(a1, (int)b2);   // 用户自己强制类型转换

显示实例化: 在函数名后的<>中制定模板参数的世纪类型

int main()
{int a1 = 10;double b = 20.0;Add<int> (a1, b2);  // 显示实例化return 0;
}

如果类型不匹配, 编译器会进行隐式类型转换, 如果无法转换成功, 编译器会报错.


如果函数参数没有模板参数, 那么就无法使用隐式实例化, 只能进行显示实例化.

// 申请一个T类型十个元素的数组并返回
template <typename T>
T *f()
{T *p = new T[10];return p;
}int main()
{int *p1 = f<int>();double *p2 = f<double>();return 0;
}

模板参数的匹配原则

  1. 一个非模板函数和一个同名的函数模板同时存在, 而且该函数模板可以被实例化为这个非模板函数
// 专门处理 int 类型的加法函数
int Add(const int &left, const int &right)
{cout << "(int) Add" << endl;return left + right;
}// 通用加法函数
template <typename T>
T Add(const T &left, const T &right)
{cout << "(template) Add" << endl;return left + right;
}int main()
{Add(1, 2);          // 有现成的优先用现成的Add<int>(1, 2);     // 如果指定显示实例化, 用函数模板
}

在这里插入图片描述


  1. 对于非模板函数和同名函数, 如果其他条件都相同, 在调用时会优先调用非模板函数而不会从该模板产生一个实例. 如果模板可以产生一个具有更好匹配的函数, 那么将选择模板.
// 专门处理 int 类型的加法函数
int Add(const int &left, const int &right)
{cout << "(int) Add" << endl;return left + right;
}// 通用加法函数
template <typename T1, typename T2>
T1 Add(const T1 &left, const T2 &right)
{cout << "(template) Add" << endl;return left + right;
}int main()
{Add(1, 2);          // 与非函数模板完全匹配, 不需要函数模板实例化Add(1, 2.0);        // 有更合适的不会进行隐式类型转换调用非函数模板, 而会直接调用函数模板实例化的实例
}

在这里插入图片描述


  1. 函数模板不允许自动类型转换, 而普通函数可以进行自动类型转换
// 专门处理 int 类型的加法函数
int Add(const int &left, const int &right)
{cout << "(int) Add" << endl;return left + right;
}// 通用加法函数
template <typename T>
T Add(const T &left, const T &right)
{cout << "(template) Add" << endl;return left + right;
}int main()
{Add(1, 2.0); // 函数模板不能进行自动类型转换, 只能调用普通函数, 传参的时候进行自动类型转化
}

在这里插入图片描述


总结

  1. 优先调用现有的普通函数
  2. 没有函数模板, 普通函数参数可以自动类型转换的, 使用普通函数.
  3. 可以通过函数模板实例化更合适的函数, 哪怕普通函数可以自动类型转换, 也用函数模板.

三. 类模板

以前写数据结构的时候, 通常会用 typedef 重命名数据结构内数据的类型.
例如 Stack 中用 typedef int STDataType, 制定 Stack 中的数据类型是 int 类型的.

但是, 这样只能保证一次只能用 int, 如果需要用到 double 的, 需要再重新写一份.

有了类模板就能很好的解决这个问题.

类模板的定义格式

template <class T1, class T2,...,class T3>
class 类模板名
{// 类内成员定义
};

例如: Stack

template <class T>
class Stack
{
public:Stack(size_t capacity = 10): _array(new T[capacity]), _capacity(capacity), _top(0){}~Stack();void push(const T &data);//...
private:T *_array;int _capacity;int _top;
};// 类外定义成员函数必须要加模板参数列表
template <class T>
Stack<T>::~Stack()
{delete[](_array);_capacity = _top = 0;
}

类外定义成员函数, 必须要加上模板参数列表声明, 并且指定类域时必须加上模板参数列表.

同时, 类模板成员函数的声明与定义必须放在同一个文件中, 否则编译器会链接失败.

类模板的实例化

类模板实例化与函数模板实例化不同, 类模板都是显示实例化, 需要在类模板名字后面跟<>, 然后将实例化的类型放在<>中即可, 类模板名字不是真正的类, 而实例化的结果才是真正的类

Stack<int> s1;
Stack<double> s2;

普通类的类名即是类型, 而类模板的类名不是类型, 类名<数据类型> 才是整个类的类型.

Stack<int>Stack<double> 不是同一个类, 他们只是同一类模板显示实例化生成的不同类.

本章完.

http://www.yayakq.cn/news/955344/

相关文章:

  • 网站开发宣传广告安惠会员管理系统
  • 做网站用什么语言数据库网页制作工具按其制作方式有
  • 深圳网站建设-新奇网络h5网页网站制作代码
  • 上海企业免费建站彩票网站建设成本
  • 蘑菇街网站怎么做网站建设面对的问题
  • 购物网站域名大小如何免费注册网站
  • 阜新网站seo专业建设目标如何表述
  • 阅读网站怎么做seo建站平台哪家好
  • 邢台提供网站设计公司哪家专业淘宝客做网站链接
  • 网站如何备案 流程图网站开发如何设置背景图片
  • 淘宝客自建网站站酷网海报素材图片
  • 如何增加网站流量同步WordPress微信公众号
  • 工业和信息化部工业文化发展中心搜索引擎优化规则
  • 手机商城网站外贸网站推荐
  • 做网站导航站的注意点两学一做知识问答网站
  • 网站上搜索的动图怎么做壁纸wordpress 图片采集
  • 网站兼容设置优化大师apk
  • 建筑局网站南充二手房
  • 广州建设网站首页影响网站速度的代码
  • 做网站后台需要什么做阿里国际网站多少钱
  • 网站上的图片多大合适做电脑网站起什么名字
  • dede网站怎么做微信小程序网站建设具体实施方案
  • 百度竞价推广是什么seo的排名机制
  • 手机上上建设网站wordpress数据库添加用户
  • 如何免费建网站网络架构和管理
  • 网站开发 外包给公司做网站需要什么
  • 用网站做邮箱吗网站 建设文档
  • 招远做网站公司利用国外网站文章图片做书营利
  • 快速建站公司有哪些网站图怎么做会高清
  • 网站建设的广告语知乎 做照片好的网站