C++:继承、模板、CRTP:谈谈C++多态设计模式(三):函数模板

news2024/11/28 0:30:27

1:模板的概念

C++中不止有 面向对象编程思想,还要泛型编程思想。而泛型编程思想的核心就是 模板

模板的建立大大提搞了复用行,C++中的模板包括 :函数模板和类模板。

2:函数模板基本语法

函数模板

概念:

     建立一个通用的函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表,比如现在有个函数 func的声明为  void func(int a) , 我们可以让其成为一个模板,形参类型与返回值类型用 虚拟的 T 表示, 那么  func函数模板的声明为  : T func(T a); 

语法

     template <typename T>

     函数声明或定义

解释:

    template -----声明创建模板

    typename ------表明后面的符号是一种数据类型,可以用 class 代替

    T ------通用的数据类型,名称可以替代,通常为大写字母。

案例

如果现在我们想实现一个能交换两个变量的值得函数,如果不使用函数模板,针对 整型,浮点型,字符型等不同数据类型的变量,我们需要分别给出对应的函数定义。

不使用函数模板的写法

#include<iostream>
using namespace std;

// 交换整型函数
void swapInt(int& a,int& b) {
	int temp = a;
	a = b;
	b = temp;
}

// 交换浮点函数
void swapFloat(float& a, float& b) {
	float temp = a;
	a = b;
	b = temp;
}

int main() {
	int a = 10, b = 20;
	float c = 10.0, d = 20.0;
	swapInt(a, b);
	swapFloat(c, d);
	cout << "a = " << a << "  b = " << b << endl;
    cout << "c = " << c << "  d = " << d << endl;
}

// 打印结果

a = 20  b = 10
c = 20  d = 10

 使用模板函数的写法

#include<iostream>
using namespace std;

// 交换函数
template<typename T>
void swapFunc(T& a,T& b) {
	T temp = a;
	a = b;
	b = temp;
}


int main() {
	int a = 50, b = 80;
	float c = 90.0, d = 100.0;
	swapFunc(a, b);
	swapFunc(c, d);
	cout << "a = " << a << "  b = " << b << endl;
	cout << "c = " << c << "  d = " << d << endl;
}

// 打印结果

a = 80  b = 50
c = 100  d = 90

总结:

1:函数模板利用关键字 template

2:  使用函数模板有两种方式: 自动类型推导,显示指定类型

3:模板的目的是为了提高复用性,将类型参数化

3:函数模板注意事项 

1: 自动类型推导:必须推导出一致的数据类型 T ,才可以使用。

 2: 模板必须要确定出T 的数据类型,才可以使用。

 

解决方案:直接在调用的时候加上 : 尖括号并给出具体类型

 

 

4:普通函数和函数模板的区别 

1: 普通函数调用时可以发生自动类型转换(隐式类型转换)

2:函数模板调用时

    ------如果利用自动类型推导,不会发生隐式类型转换

   ------如果利用显示指定类型的方式,可以发生隐式类型转换

3:建议使用显示指定类型的方式,调函函数模板时,因为可以自己确定通用类型T

5: 普通函数与函数模板的调用规则 

1: 如果函数模板和普通函数都可以实现功能,那么优先使用普通函数

2: 可以通过空模板参数列表来强制调用函数模板

3:函数模板也可以有 重载的发生。

4:如果函数模板可以产生更好的匹配,优先调用函数模板

虽然通过隐式转换来调用普通函数,但是函数模板也可以推导出T 为char ,但是优先匹配函数模板

 

6: 函数模板的局限性 

局限性: 模板的通用性并不是万能的

案例: 我们编写一个函数模板事项对比两个形参,如果相等则返回 true,  对于内置的数据类型(int , char ,long , double) 可以直接使用 == 进行对比,但是对弈一些自定义的数据类型就不能直接使用 == 进行对比。

例如:我们有个 Person类,里面有string 类型的成员变量 name, 还有int 类型的成员变量 age, 如果这两个成员变量都相等则表明这两个变量相等。如果直接向函数模板传入Person类并进行对比,那么是会报错的。

#include <iostream>
#include <string>
using namespace std;

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};

//普通函数模板
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test02()
{
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	bool ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "p1 == p2 " << endl;
	}
	else
	{
		cout << "p1 != p2 " << endl;
	}
}

int main() {
	test02();
	system("pause");
	return 0;
}

// 打印内容 

已启动生成…
1>------ 已启动生成: 项目: MainDemo6, 配置: Debug Win32 ------
1>main.cpp
1>D:\C++\MainDEMO6\main.cpp(21,8): error C2676: 二进制“==”:“T”不定义该运算符或到预定义运算符可接收的类型的转换
1>        with
1>        [
1>            T=Person
1>        ]
1>D:\C++\MainDEMO6\main.cpp(35): message : 查看对正在编译的函数 模板 实例化“bool myCompare<Person>(T &,T &)”的引用
1>        with
1>        [
1>            T=Person
1>        ]
1>已完成生成项目“MainDEMO6.vcxproj”的操作 - 失败。
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========

解决方案:为这些特定的类型提供具体化的模板

#include<iostream>
using namespace std;

#include <string>

class Person
{
public:
	Person(string name, int age)
	{
		this->m_Name = name;
		this->m_Age = age;
	}
	string m_Name;
	int m_Age;
};

//普通函数模板
template<class T>
bool myCompare(T& a, T& b)
{
	if (a == b)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//具体化,显示具体化的原型以template<>开头,并通过名称Person来指出类型
//具体化优先于常规模板
template<> bool myCompare(Person& p1, Person& p2)
{
	if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void test01()
{
	int a = 10;
	int b = 20;
	//内置数据类型可以直接使用通用的函数模板
	bool ret = myCompare(a, b);
	if (ret)
	{
		cout << "a == b " << endl;
	}
	else
	{
		cout << "a != b " << endl;
	}
}

void test02()
{
	Person p1("Tom", 10);
	Person p2("Tom", 10);
	//自定义数据类型,不会调用普通的函数模板
	//可以创建具体化的Person数据类型的模板,用于特殊处理这个类型
	bool ret = myCompare(p1, p2);
	if (ret)
	{
		cout << "p1 == p2 " << endl;
	}
	else
	{
		cout << "p1 != p2 " << endl;
	}
}

int main() {
	test01();
	test02();
	system("pause");
	return 0;
}

// 打印结果
a != b
p1 == p2

7: 总结

1: 利用具体化的模板,可以解决自定义类型的通用化

2:学习函数模板并不是为了写模板,而是能在 STL中能够运用系统提供的模板

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

细粒度图像分类论文研读-2018

文章目录Object-Part Attention Model for Fine-grained Image Classification&#xff08;by localization- classification subnetwork&#xff09;AbstractIntroductionObject- Part Attention ModelObject- Part Spatial Constraint ModelOur OPAM ApproachObject-level At…

Flink从入门到放弃—Stream API—clean()方法

文章目录导航clean()案例贴上源码导航 涉及到文章&#xff1a; Flink从入门到放弃—Stream API—Join实现&#xff08;即多流操作&#xff09; Flink从入门到放弃—Stream API—常用算子&#xff08;map和flatMap&#xff09; Flink从入门到放弃—Stream API—常用算子(filter…

讲解Redis的主从复制

Redis 主从复制1 主从复制2 作用3 主从复制架构图4 搭建主从复制5 使用规则1 主从复制 主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据 无法解决: 1.master节点出现故障的自动故障转移 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到…

数据挖掘的步骤有哪些?

所谓数据挖掘就是从海量的数据中&#xff0c;找到隐藏在数据里有价值的信息。因为这个数据是隐式的&#xff0c;因此想要挖掘出来并不简单。那么&#xff0c;如何进行数据挖掘呢&#xff1f;数据挖掘的步骤有哪些呢&#xff1f;一般来讲&#xff0c;数据挖掘需要经历数据收集、…

openEuler 倡议建立 eBPF 软件发布标准

eBPF 是一个能够在内核运行沙箱程序的技术&#xff0c;提供了一种在内核事件和用户程序事件发生时安全注入代码的机制&#xff0c;使得非内核开发人员也可以对内核进行控制。随着内核的发展&#xff0c;eBPF 逐步从最初的数据包过滤扩展到了网络、内核、安全、跟踪等&#xff0…

软件测试之测试用例评审

一、评审目的 一般来说&#xff0c;参加测试用例评审的人员包括对应项目的产品人员、设计人员、开发人员和测试人员。 图1-1 测试用例评审相关人员 测试用例评审会议的发起者一般是测试人员&#xff0c;既然我们是发起者&#xff0c;那我们发起这个会议的目的是什么呢&#x…

【Java开发】 Spring 11 :Spring Boot 配置 Web 运行参数并部署至服务器

Spring Boot 项目开发结束后的工作便是运维&#xff0c;简单来说需要配置 Web 运行参数和项目部署两大工作&#xff0c;本文将尽可能详细地给大家讲全&#xff01; 目录 1 定制 Web 容器运行参数 1.1 运行参数介绍 1.2 项目搭建 ① 通过 IDEA Spring Initializr 创建项目 …

使用nginx代理服务器上的docker容器接口

假如项目通过自动化部署在了docker容器里面&#xff1a;教程在这里vue使用dockernodenginxlinux自动化部署_1024小神的博客-CSDN博客 怎么将nginx通过域名绑定到这个容器呢&#xff1f; 例如我们将一个二级域名绑定second.1024shen.com/#/ 到我们的服务 我们需要先在域名解析…

阿里P8专家整理的面试秘籍,我看了三个月,成功入职京东,税前30K

入职京东&#xff0c;月薪30K 今年三月份的时候&#xff0c;我从上一家外包公司裸辞。那时正值疫情期间&#xff0c;实在受不了公司的压迫&#xff0c;毅然决然的选择了离职。 卧薪尝胆三个月后&#xff0c;才收到京东的offer&#xff0c;谈到了30k的月薪顺利入职。 本来那时…

DPDK源码分析之l2fwd

什么是L2转发 2层转发&#xff0c;即对应OSI模型中的数据链路层&#xff0c;该层以Mac帧进行传输&#xff0c;运行在2层的比较有代表性的设备就是交换机了。 当交换机收到数据时&#xff0c;它会检查它的目的MAC地址&#xff0c;然后把数据从目的主机所在的接口转发出去。 交…

SSM 学习管理系统

SSM 学习管理系统 SSM 学习管理系统 功能介绍 首页 图片轮播展示 网站公告 学生注册 教师注册 课程资料 视频学习 友情链接 资料详情 学习进度 评论 收藏 后台管理 登录 管理员管理 修改密码 网站公告管理 友情链接管理 轮播图管理 学生管理 班级管理 我的班级管理 教师管理…

微信小程序 | 小程序的内置组件

&#x1f5a5;️ 微信小程序专栏&#xff1a;微信小程序 | 小程序的内置组件 &#x1f9d1;‍&#x1f4bc; 个人简介&#xff1a;一个不甘平庸的平凡人&#x1f36c; ✨ 个人主页&#xff1a;CoderHing的个人主页 &#x1f340; 格言: ☀️ 路漫漫其修远兮,吾将上下而求索☀️…

【轻量级开源ROS 的机器人设备(4)】--(3)通信实现

前文链接 【轻量级开源ROS 的机器人设备&#xff08;4&#xff09;】--&#xff08;2&#xff09;通信实现_无水先生的博客-CSDN博客 六、数据流 数据流 虽然 XML-RPC 为远程方法调用提供了一种简单而干净的协议&#xff0c;但其冗长和以文本为中心的编码使其不适合高带宽和低…

手把手分享:如何将小程序游戏引入自有APP?(Android篇)

上一期的为大家分享了&#xff1a;如何在iOS中引入FinClip SDK&#xff0c;并将小程序游戏运行到自有App 中。点击查看&#xff1a;&#x1f449;手把手系列&#xff1a;如何将小程序游戏引入自有APP&#xff1f;&#xff08;iOS篇&#xff09; 本周继续分享如何在Android系统…

小红书如何做推广增粉?怎样让小红书快速增加粉丝?

互联网时代&#xff0c;任何什么平台的推广都需要流量&#xff0c;没有流量的账号是做不起来的&#xff0c;也就没有宣传或是转化的效果。 小红书账号粉丝数量和权重是成正比的&#xff0c;涨粉越多的账号&#xff0c;说明越受到用户的喜欢&#xff0c;账号笔记的数据就会越好…

5G“新引擎”,助力矿山向无人化、智慧化转型

导语 | 5G 商用已过去三年&#xff0c;其发展已步入规模化应用的关键期。无论是在诸如矿山、港口远程驾驶的行业应用领域&#xff0c;还是在面向C端的智能汽车、自动驾驶方面&#xff0c;都得到了广泛应用。今天&#xff0c;我们特邀了三一智矿的董事长、腾讯云 TVP 行业大使马…

java面试强基(23)

什么是线程死锁?如何避免死锁? ​ 线程死锁描述的是这样一种情况&#xff1a;多个线程同时被阻塞&#xff0c;它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞&#xff0c;因此程序不可能正常终止。 上面的例子符合产生死锁的四个必要条件&#xff1…

提高短视频的收藏下载和转发率的方法,我们可以不做但不能不会

想要提高收藏和下载&#xff0c;那就要提高你内容的价值感和获得感。 我们要清晰的知道收获感不等同于真正的收获。那我们的做法就是给出冗余的有用&#xff0c;给出熟悉的陌生&#xff0c;给出精准的表达。那这是提高收藏转发的方法。 我们看到好看的视频&#xff0c;想分享视…

Hack the box -- Responder靶机

这个靶机记录一下。。感觉会用到。 任务1 当使用IP地址访问web服务时&#xff0c;我们被重定向到的域是什么? 这里我们访问一下ip&#xff0c;然后重定向了 FLAG:unika.htb 任务2 服务器上使用哪种脚本语言生成网页? 这里因为重定向域的问题&#xff0c;我们是访问不了的会报…

408 | 【2022年】计算机统考真题 自用回顾知识点整理

一、数据结构 T1:时间复杂度 ——直接求程序执行的次数 T5:哈夫曼树(最优二叉树)与哈夫曼编码 定义 结点带权路径长度:从根到任一节点的路径长度(经过的边数)与该结点权值的乘积树的带权路径长度WPL:所有叶节点的带权路径长度之和 哈夫曼树:WPL最小的二叉树哈夫曼树的…