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

C++入门七式——模板初阶

目录

函数模板

函数模板概念

函数模板格式

函数模板的原理

函数模板的实例化

模板参数的匹配原则

类模板

类模板的定义格式

类模板的显式实例化 


当面对下面的代码时,大家会不会有一种无力的感觉?明明这些代码差不多,只是因为类型不同,就要多写几行代码。如果有泛型编程该有多好! 

void swap(int& left, int& right)
{int tmp = left;left = right;right = tmp;
}
void swap(double& left, double& right)
{double tmp = left;left = right;right = tmp;
}
void swap(char& left, char& right)
{char tmp = left;left = right;right = tmp;
}

虽然在这种情况下,函数重载也可以实现,但是有以下几个不好的地方:

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

那是否能告诉编译器一个模子,让编译器根据不同的类型利用该模子生成代码呢?这就要讲到我们今天的内容了——模板。

函数模板

函数模板概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化根据实参类型产生函数的特定版本。

函数模板格式

#include<iostream>
using namespace std;
template <typename t>
//typename是用来定义模板参数关键字,也可以用class(不能用struct
void swap(t& x, t& y)
{t tmp = x;x = y;y = tmp;
}
int main()
{return 0;
}

函数模板的原理

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

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

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

1.隐式实例化:模板参数根据实参自动推演。

#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;//隐式实例化add(a1, a2);add(d1, d2);//在模板中,编译器一般不会进行类型转换操作,因为一旦转化出现问题,编译器就需要背黑锅//add(a1, d1);//有两种解决方法:1.用户自己来强制转化2.使用显式实例化add(a1,(int)d1);return 0;
}

2. 显式实例化:在函数名后的<>中指定模板参数的实际类型

int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;//显式实例化add<int>(a1, a2);add<double>(d1, d2);add<int>(a1, d1);return 0;
}

模板参数的匹配原则

  • 一个非模板函数和一个同名函数模板可以同时存在 ,而且该函数模板还可以被实例化为这个非模板函数(现成的非模板函数优先)。

#include<iostream>
using namespace std;
template<typename T>
T add(T x, T y)
{cout << "模板" << endl;return x + y;
}
int add(int x, int y)
{cout << "现成" << endl;return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;add(a1, a2);return 0;
}

 

  • 对于非模板函数和一个同名函数,我们都可以调用,但会调用更匹配的。
#include<iostream>
using namespace std;
template<typename T1,typename T2>
T1 add(T1 x, T2 y)
{cout << "模板" << endl;return x + y;
}
int add(int x, int y)
{cout << "现成" << endl;return x + y;
}
int main()
{int a1 = 10, a2 = 22;double d1 = 10.23, d2 = 45.23;add(a1, d2);return 0;
}

 

 可以看出编译器会优先调用更匹配的模板,即使它比较麻烦。

类模板

基本都是显式实例化,因为无法借助数来推是什么类型

类模板的定义格式

template<class T1, class T2>
class t//类模板名
{};

举例:

#include<iostream>
using namespace std;
template<class T>
class stack
{
public:stack(size_t capacity = 4){_array = new T[capacity];_capacity = capacity;_size = 0;}void Push(const T& data);
private:T* _array;size_t _capacity;size_t _size;
};
template<class T>
void stack<T>::Push(const T& data)
{_array[_size] = data;++_size;
}
int main()
{stack<int>st1;return 0;
}

类模板的显式实例化 

实例化模板需要在类模板后加<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

int main()
{stack<int>st1;return 0;
}

 

 

 

相关文章:

  • Nacos启动报错
  • 软件测试行业核心知识点的系统化梳理
  • 使用 TensorFlow 和 Keras 构建 U-Net
  • Python语法系列博客 · 第9期[特殊字符] 函数参数进阶:*args、**kwargs 与参数解包技巧
  • 混合精度训练中的算力浪费分析:FP16/FP8/BF16的隐藏成本
  • 深度学习--mnist数据集实现卷积神经网络的手写数字识别
  • 探索大语言模型(LLM):Transformer 与 BERT从原理到实践
  • 【OpenGL】OpenGL学习笔记-1:VS2019配置OpenGL开发环境
  • PR第一课
  • Arduino项目中硬件包括哪些部分
  • 【MATLAB海洋专题】历史汇总
  • 链表面试题
  • 用思维导图解锁计算机科学导论的知识宝库
  • 取值运算符*和地址运算符
  • MYSQL初阶(暂为自用草稿)
  • [密码学基础]GM/T 0018-2023 密码设备应用接口规范深度解析:技术革新与开发者实践
  • 【测试文档】项目测试文档,测试管理规程,测试计划,测试文档模版,软件测试报告书(Word)
  • 使用C语言的cJSON中给JSON字符串添加转义
  • C++中chrono计时器的简单使用示例
  • MCP协议驱动的全自动光催化甲烷偶联实验平台构建及实现方案
  • 旧电梯换新如何分摊费用?低楼层可以不出钱吗?上海闵行举办讨论会
  • 上海召开全市加强社会治安综合治理中心规范化建设工作推进会
  • 瑞安房地产王颖:房地产市场看到很好的信号,上海项目销售压力不大
  • 中国正在俄罗斯国内生产武器?外交部:坚决反对无端指责和政治操弄
  • 美国开始从叙利亚撤出数百人,分析人士担忧“伊斯兰国”威胁再起
  • 一周文化讲座|读书是通往世界的路