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

C++中的模版初识

目录

1.泛型编程

2.函数模板

什么是函数模板

如何定义函数模板

函数模板的原理

如何使用函数模板

隐式实例化

显示实例化

模板参数的匹配原则

3.类模板

如何定义类模板

如何使用类模板


1.泛型编程

所有的编程语言都具有各种各样的数据类型,不同数据类型的数据可能需要相同的功能。这个时候,如果是C语言的话,只能针对每种数据类型单独写一个函数,并且函数名还不能相同,如果是C++的话,虽然支持同名函数的出现,但是,也仅仅是函数名相同,针对不同的数据类型还是需要单独实现一个函数。于是,C++就引入了一种无关类型的编程方式 —— 泛型编程

在编程的世界中,不同类型的数据就好像是不同类型的原材料一般,在泛型编程的世界中,我们并不关心原材料的类型,不管你给我什么类型我都实现同样的功能;我们可以对比生活中的例子来理解,不知道大家有没有见过月饼的制作,过程大概如下:

  • 用皮把馅料包起来。
  • 然后塞进模板。
  • 然后拍出来。

在这个过程中,模板并不关心是什么馅料,不管你是什么馅料,都能形成该卸料对应的月饼。没错,泛型编程也是如此,我们告诉编译器一个模板,编译器根据不同类型的数据利用该模板生成对应的代码。

在C++中,模板有两种,一种是函数模板,一种是类模板。(哦吼,这让我想起了友元函数和友元类)下面依次介绍

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


2.函数模板

什么是函数模板

月饼模板是用来生产月饼的,那函数模板就是用来生产函数的。

函数模板是一个蓝图,本身并不是函数。

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


如何定义函数模板

使用格式如下:

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}

  • template是定义模板的关键字
  • typename是定义类型参数的关键字
  • T1……Tn是模板参数
  • 其中,typename可以用class代替。

举个例子,实现一个通用的交换函数:

template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}

函数模板的原理

函数模板会根据参数类型生成特定版本的函数,这个工作是编译器来做的。在编译器编译阶段,调用函数模板的时候,编译器根据传入类型的参数推演实例化出该类型的函数。

以Swap函数为例:当我们传入int类型的数据时,编译器就会根据模板推演实例化出一份针对int类型的交换函数;如果传入的是char类型的数据,就会推演实例化出一份针对char类型的函数。


如何使用函数模板

函数模板并不是最终使用的函数,需要推演实例化出针对具体类型的函数才能使用,这个过程就叫做函数模板的实例化。实例化分为两种:隐式实例化显示实例化。

隐式实例化

隐式实例化就是让编译器根据实参推演模板参数的具体类型。

像这个例子中就是通过隐式实例化使用模板参数:

显示实例化

显示实例化的格式如下:

  • 函数名 <类型> (参数)。其实就是在调用函数的时候,在函数后添加一对<>,并在<>中指明类型。

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

注意:前面示范的是单个模板参数的情况,多个模板参数的情况只需要类比函数参数使用即可。


模板参数的匹配原则

我们以 一个非模板函数和一个同名的函数模板同时存在为例,看下面这段代码:

// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}// 通用加法函数
template<class T>
T Add(T left, T right)
{return left + right;
}int main()
{Add(1, 2); // 与非模板函数匹配,编译器不需要特化Add<int>(1, 2); // 调用编译器特化的Add版本Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数return 0; 
}

我们可以这样理解,非模板函数是家里做的饭菜,函数模板生成的函数是外卖;可以形象的总结一下:

  • 合适匹配的情况下,有现成的就吃现成。
  • 没有现成的,就点外卖吃。
  • 如果现成的不符合胃口,也点外卖。

注意,普通函数可以进行自动类型转换,函数模板不允许进行自动类型转换。(如果转换出来不是我们想要的,编译器就要背黑锅了,毕竟,谁都不愿意背黑锅)


3.类模板

C++中不仅仅有函数模板,还有类模板。比如:我们使用数据结构的时候,可能需要存储int类型的数据,可能需要存储char类型的数据,甚至需要存储自定义类型的数据,这个时候,不就又可以使用模板了吗?

如何定义类模板

定义类模板格式如下:

  • 和函数模板的定义大差不差。 

我们以数据结构中的栈为例:

// 类模板
template<class T>
class Stack
{
public:Stack(int capacity = 4){cout << "Stack(int capacity = 4)" << endl;_arr = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){cout << "~Stack()" << endl;delete[] _arr;_arr = nullptr;_top = 0;_capacity = 0;}
private:T* _arr;int  _top;int  _capacity;
};

当类模板的成员函数的声明和定义分离,且再同一个文件中的时候,需要再定义的前面加模板参数列表。

如下所示:

// 类模板
template<class T>
class Stack
{
public:~Stack();
private:T* _arr;int  _top;int  _capacity;
};template<class T>
Stack<T>::~Stack()
{cout << "~Stack()" << endl;delete[] _arr;_arr = nullptr;_top = 0;_capacity = 0;
}

注意:类模板的声明和定义不能分在不同的文件,否则会造成链接错误。


如何使用类模板

类模板也是模板,使用的时候也需要进行推演实例化,只不过,类模板只能显示实例化。

并且,对于类模板来说,类名不是类型,类名+<模板参数类型> 才是类型

使用方式如下:

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

推演过程如下: 


http://www.mrgr.cn/news/65192.html

相关文章:

  • python爬取旅游攻略(1)
  • 关于Linux系统调试和性能优化技巧有哪些?
  • Rust 力扣 - 54. 螺旋矩阵
  • C/C++ 随机数生成方法
  • 软考背诵笔记
  • scala的属性访问权限
  • 服务器技术(一)--Linux基础入门
  • 克服奖励欺骗:Meta发布全新后训练方式CGPO,编程水平直升5%,打破RLHF瓶颈
  • 哈尔滨华时信息技术有限公司,特色之处见怎么样
  • Go并发编程之原子操作syncatomic
  • YOLO11论文 | 重要性能衡量指标、训练结果评价及分析及影响mAP的因素【发论文关注的指标】
  • 一文搞懂Apk的各种类型
  • Verilog HDL基础
  • 基于web的中小学成绩管理系统的设计与实现
  • Web-高校教务考试管理系统
  • 用户程序发出磁盘IO请求后,系统的处理流程
  • 供应SW1102集成氮化镓直驱的准谐振模式反激控制IC
  • Go:struct结构体和继承
  • 华为独家揭秘:AI时代产品经理成长宝典——《人工智能产品经理》168页首发
  • 遗传算法与深度学习实战(21)——使用差分搜索自动超参数优化
  • 供应SW1108P集成氮化镓直驱的高频准谐振IC
  • mac 打开访达快捷键
  • 【Linux内核设计思想】三、Linux内核的启动过程
  • ORACLE 删除archivelog日志
  • Nginx 的基础架构解析(上)
  • 正向代理模块