15. C++泛型与符号重载


【泛型编程】

若多组类型不同的数据需要使用相同的代码处理,在C语言中需要编写多组代码分别处理,这样做显然太过繁琐,C++增加了虚拟类型,使用虚拟类型可以实现一组代码处理多种类型的数据。

虚拟类型是暂时不确定的数据类型,它在定义时不指定具体类型,而是在使用时指定类型,可以用于单个数据类型,也可以用于数组、结构体,使用虚拟类型编程也称为泛型编程,意为广泛类型。

使用虚拟类型的代码称为模板,但是全局数据不能使用虚拟类型,全局数据也无需定义为模板。

全局函数模板

函数模板的参数、返回值可以使用虚拟类型,参数与返回值的数量必须相同,只是类型不同。

#include <iostream>
template <typename T>   //使用template关键词定义虚拟类型,T为虚拟类型名称
T add(T t1, T t2)
{
	return t1+t2;
}
int main()
{
	printf("%d\n", add(1, 2));          //T指定为int类型
	printf("%f\n", add(0.1f, 0.2f));    //T指定为float类型
	
	return 0;
}

虚拟类型使用template关键词定义,也可以使用class定义,可以在<>符号内定义多个虚拟类型,不同虚拟类型使用,符号隔开,但是每个定义的虚拟类型都必须使用,否则编译报错。

函数模板内可以使用多个虚拟类型,执行函数模板时需要为其内部虚拟类型指定具体类型,当多次执行函数模板并为虚拟类型设置不同的具体类型时,编译器会将函数模板编译为多个函数,分别使用不同的指令处理数据,上述代码中的add函数实际上会被编译器编译成两个函数,分别使用整数运算指令和浮点数运算指令处理数据,模板只是简化了程序员的工作量,并没有减少程序编译后的代码量。

成员函数模板

#include <iostream>
class math
{
public:
	template <typename T>    //定义虚拟类型
	T add(T t1, T t2) const
	{
		return t1+t2;
	}
};
int main()
{
	math math1;
	printf("%d\n", math1.add(1, 2));
	printf("%f\n", math1.add(0.1f, 0.2f));
	
	return 0;
}

类模板

成员数据使用虚拟类型的类称为类模板。

#include <iostream>
template <typename T>
class math
{
private:
	T a,b;
	
public:
	math(T t1, T t2)
	{
		a = t1;
		b = t2;
	}
	
	T add() const
	{
		return a+b;
	}
};
int main()
{
	math<int> math1(1, 2);         //创建对象时需要使用<>符号设置数据类型
	printf("%d\n", math1.add());
	
	math<float> math2(0.1, 0.2);
	printf("%f\n", math2.add());
	
	return 0;
}

成员数组模板

虚拟类型用于类成员数组时可以额外定义一个变量,此变量用于设置数组模板的长度,从而实现数组的类型、长度都在定义时临时确定。

#include <iostream>
template <typename T, int i>    //变量i设置数组长度
class array
{
private:
	T a[i];
	
public:
	//......
};
int main()
{
	array<int, 5> array1;      //成员数组类型为int,包含5个元素
	array<float, 6> array2;    //成员数组类型为float,包含6个元素
	
	return 0;
}


【符号重载】

在C++中可以借助operator关键词将语法中的某些符号、关键词当做函数名,从而重新定义此符号的功能,这种函数称为符号函数,调用符号函数执行时可以无需指定operator关键词,直接使用重载的符号即可,全局函数和成员函数都可以设置为符号函数。

使用符号函数会让代码更简洁,比如连接字符串函数使用+符号作为函数名,即可通过+符号连接两个字符串。


可重载的符号如下:

+  -  *  /  ++  --  %  <<  >>
&&  ||  !  &  |  ~  ^
<  >  ==  !=  >=  <=
=  +=  -=  *=  /=  %=  ^=  &=  |=  >>=  <<=
,  ()  []
->  ->*
new  delete  new[]  delete[]


符号重载注意事项:
1.只能使用C++语法中原有符号,不能使用C++语法没有的符号。
2.= () [] -> 这四种符号只能用于成员函数,不能用于全局函数。
3.重载不同符号时,函数可以设置的参数个数不同。
4.重载相同符号时,全局函数与成员函数可以设置的参数个数不同。
5.重载不同符号有不同的限制,比如:重载-符号不能计算两个double数据相加、重载%符号不能只有一个操作数、重载new的函数返回值只能是void类型指针。


重载 + 符号

重载+符号连接固定长度字符串对象,并返回连接结果。

#include <iostream>
class string
{
public:
	char strvar[100] = {0};
	
	/* operator+符号函数连接string对象 */
	string operator+(const string & conobj) const
	{
		string result;              //存储连接结果
		unsigned int strlen = 0;    //存储本类strvar空字符下标
		unsigned int conlen = 0;    //存储conobj.strvar空字符下标
		
		result.strvar[0] = 0;       //初始空字符
		
		/* 查询本类strvar空字符下标,若没有空字符则当做不合规string对象处理,strlen = 0 */
		for(int i = 0; i < 100; i++)
		{
			if(strvar[i] == 0)
			{
				strlen = i;
				break;
			}
		}
		
		/* 查询conobj.strvar空字符下标 */
		for(int i = 0; i < 100; i++)
		{
			if(conobj.strvar[i] == 0)
			{
				conlen = i;
				break;
			}
		}
		
		/* result连接本类strvar */
		if(strlen != 0)
		{
			result = *this;
		}
		
		/* result连接conobj.strvar */
		if(conlen != 0)
		{
			if(strlen == 0)
			{
				result = conobj;
			}
			else
			{
				for(int i = 0; strlen<99 && i<=conlen; i++)
				{
					result.strvar[strlen] = conobj.strvar[i];
					strlen++;
				}
				
				result.strvar[99] = 0;    //确保末尾元素是空字符
			}
		}
		
		return result;
	}
	
	/* 重载operator+符号函数,连接字符串 */
	string operator+(const char * conobj) const
	{
		string result;
		unsigned int strlen = 0;
		unsigned int conlen = 98;    //若字符串长度超标,则最多使用99个字符
		
		result.strvar[0] = 0;
		
		/* 查询本类strvar末尾下标 */
		for(int i = 0; i < 100; i++)
		{
			if(strvar[i] == 0)
			{
				strlen = i;
				break;
			}
		}
		
		/* 查询conobj末尾下标,只需查询99个字节 */
		for(int i = 0; i < 99; i++)
		{
			if(conobj[i] == 0)
			{
				conlen = i;
				break;
			}
		}
		
		/* 连接本类strvar */
		if(strlen != 0)
		{
			result = *this;
		}
		
		/* 连接conobj */
		if(conlen != 0)
		{
			for(int i = 0; strlen<99 && i<=conlen; i++)
			{
				result.strvar[strlen] = conobj[i];
				strlen++;
			}
			
			result.strvar[99] = 0;
		}
		
		return result;
	}
};
int main()
{
	string ali = {"阿狸"};
	string taozi = {"桃子"};
	string zoo = ali + taozi;      //调用ali.operator+函数,连接string对象
	printf("%s\n", zoo.strvar);
	
	zoo = zoo + "喜羊羊美羊羊";      //调用zoo.operator+函数,连接字符串
	printf("%s\n", zoo.strvar);
	
	return 0;
}


重载 = 符号

重载=符号修改动态长度字符串对象,字符串成员定义为私有,只能通过operator=符号函数修改。

#include <iostream>
#include <string.h>
class string
{
private:
	char * strvar;
	
public:
	string()
	{
		strvar = new char;
		*strvar = 0;
	}
	
	string(const char * assobj)
	{
		size_t asslen = strlen(assobj); 
		
		strvar = new char[asslen+1];
		strcpy(strvar, assobj);
		strvar[asslen+1] = 0;     //末尾空字符
	}
	
	~string()
	{
		delete [] strvar;
	}
	
	/* 返回字符串地址 */
	const char * get() const
	{
		return strvar;
	}
	
	void operator=(const char *assobj)
	{
		size_t asslen = strlen(assobj);
		
		/* 释放旧内存 */
		delete [] strvar;
		
		/* 申请新内存 */
		strvar = new char[asslen+1];
		
		/* 内存赋值 */
		strcpy(strvar, assobj);
		strvar[asslen+1] = 0;
	}
};

int main()
{
	string zoo("阿狸");
	printf("%s\n", zoo.get());
	
	zoo = "喜羊羊";
	printf("%s\n", zoo.get());
	
	return 0;
}


 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp在页面中中获取pages.json下pages设置navigationBarTitleText这个值?uniapp获取页面标题

一、问题描述 有个需求就是,在app.vue页面中首先会隐藏所有页面的title,然后在相应的页面会判断当前环境是否是在微信浏览器内&#xff0c;如果不是&#xff0c;则还原标题。 二、解决方法 在 pages.json 文件中设置 navigationBarTitleText&#xff0c;例如&#xff1a; {&qu…

OpenCascade源码剖析:Handle类

Handle其实就是智能指针的上古版本&#xff0c;了解一点C11的应该对shared_ptr非常熟悉&#xff0c;那么你就把Handle当做shared_ptr来理解就没有任何问题了。 不过OCCT的Handles是侵入式的实现&#xff0c;前面讲过Standard_Transient类提供了引用计数机制&#xff0c;这个就…

Missing type map configuration or unsupported mapping

今天开发的时候突然遇到这么一个问题&#xff0c;可以确定的是不是AutoMap的问题&#xff0c;因为项目中其他接口都是好好的&#xff0c;只有新加的这个控制器不行&#xff0c;排查了一下&#xff0c;少了映射配置&#xff0c;在这里加上映射关系即可&#xff0c;大意了。

egg如何写单元测试

优秀的代码需要有单元测试进行质量保证&#xff0c;每个测试用例都给应用的稳定性提供了一层保障。 测试目录结构 我们约定 test 目录为存放所有测试脚本的目录&#xff0c;测试所使用到的 fixtures 和相关辅助脚本都应该放在此目录下。 测试文件的目录和我们需要测试的文件目…

HTML—常用标签

常用标签&#xff1a; 标题标签&#xff1a;<h1></h1>......<h6></h6>段落标签&#xff1a;<p></p>换行标签&#xff1a;<br/>列表&#xff1a;无序列表<ul><li></li></ul> 有序列表<ol>&…

Python的数据库编程基础知识

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd;如果停止&#xff0c;就是低谷&#xf…

[HackMyVM]靶场 Zeug

kali:192.168.56.104 主机发现 arp-scan -l # arp-scan -l Interface: eth0, type: EN10MB, MAC: 00:0c:29:d2:e0:49, IPv4: 192.168.56.104 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.56.1 0a:00:27:00:00:05 (Un…

力扣hot100:240.搜索二维矩阵II(脑子)

吉大21级算法分析与设计的一道大题&#xff0c;由于每一行都是排好序的直接逐行二分 可以达到&#xff1a;O(mlogn)。但是这里追求更广的思路可以使用其他方法。 矩阵四分&#xff1a; 在矩阵中用中心点比较&#xff0c;如果target大于中心点的值&#xff0c;则由于升序排列&am…

排序二叉树

参考 Binary Search Tree Visualization (usfca.edu) 一、构建排序二叉树 注意引用 tree /*** 构造二叉排序树* param tree* param x*/ void buildTree(BSTree &tree,ElementType &x){if (treeNULL){tree(BSTree) calloc(1, sizeof(BSTNode));tree->datax;//注意ret…

Python算法题集_搜索二维矩阵

Python算法题集_搜索二维矩阵 题51&#xff1a;搜索二维矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵展开为列表二分法】2) 改进版一【行*列区间二分法】3) 改进版二【第三方模块】 4. 最优算法5. 相关资源 本文为Python算法题集之…

bugku-misc隐写

下载文件&#xff0c;解压得到图片 没看到信息&#xff0c;试着查看图片属性 看到图片宽高不一致&#xff0c;猜测可能需要改变图片长度或者宽度 试着把图片变大&#xff0c;十进制500转16进制 得到1f4 用010打开图片 第二行第一个为宽&#xff0c;第二个为高&#xff0c;A…

【计网】TCP协议安全与风险:深入探讨网络通信的基石

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 &#x1f310;前言 &#x1f512;正文 TCP (Transmission Control Protocol): UDP (User Datagram Protocol): HTTP (Hypertext Transfer …

WordPress建站入门教程:如何创建菜单和设置前端导航菜单?

前面我们跟大家分享了WordPress如何上传安装WordPress主题&#xff0c;但是启用主题后前端没有看到有导航菜单&#xff0c;这是因为我们还没有创建菜单和设置导航菜单。 JianYue主题导航菜单和右上角菜单 今天boke112百科就继续跟大家分享WordPress站点如何创建菜单和设置前端…

java-抢红包一些简单概念

抢红包&#xff0c;比如微信中抢红包&#xff0c;红包金额分配使用的是二倍均值算法。 二倍均值拆包&#xff1a; 拆包要求:所有人抢到的金额之和等于红包总额&#xff0c;每个人最少抢到 0.01 元&#xff0c;每个人抢到的红包金额不要相差太大二倍均值法:假设红包总金额是X&…

2024最新版正规视频影视系统源码/APP+H5视频影视源码

全新魅思V20正规视频影视系统源码&#xff0c;APPH5视频影视源码。会员花费三千购入的&#xff0c;具体搭建教程放压缩包了&#xff01; 有兴趣的下载自行研究吧&#xff0c;搭建一共要用到3个域名&#xff0c;可以拿二级域名搭建。

奖励建模(Reward Modeling)实现人类对智能体的反馈

奖励建模&#xff08;Reward Modeling&#xff09;是强化学习中的一个重要概念和技术&#xff0c;它主要用于训练智能体&#xff08;如AI机器人或大型语言模型&#xff09;如何更有效地学习和遵循人类期望的行为。在强化学习环境中&#xff0c;智能体通过尝试不同的行为获得环境…

4月9日至10日Hack.Summit 2024亚洲首秀:Web3开发者齐聚香港数码港

Hack.Summit() 是一系列 Web3 开发者大会。本届活动将于 2024 年 4 月 9 日至 4 月 10 日在香港数码港举行。自十年前首次举办以来&#xff0c;此次会议标志着 Hack.Summit() 首次在亚洲举办&#xff0c;香港被选为首次亚洲主办城市&#xff0c;这对 Hack VC 和该地区都具有重要…

【Servlet】Servlet 详解(使用+原理)

文章目录 1. Servlet 介绍1.1 什么是 Servlet1.2 Servlet 的主要工作 2. Servlet 程序创建步骤2.1 创建项目2.2 引入依赖2.3 创建目录2.4 编写代码2.5 打包程序2.6 部署程序2.7 验证程序 3. 使用 Smart Tomcat 进行部署3.1 安装 Smart Tomcat3.2 配置 Smart Tomcat3.3 使用 Sma…

React-Redux中actions

一、同步actions 1.概念 说明&#xff1a;在reducers的同步修改方法中添加action对象参数&#xff0c;在调用actionCreater的时候传递参数&#xff0c;数会被传递到action对象payload属性上。 2.reducers对象 说明&#xff1a;声明函数同时接受参数 const counterStorecre…

【Python】科研代码学习:三 PreTrainedModel, PretrainedConfig

【Python】科研代码学习&#xff1a;三 PreTrainedModel, PretrainedConfig 前言Models : PreTrainedModelPreTrainedModel 中重要的方法 tensorflow & pytorch 简单对比Configuration : PretrainedConfigPretrainedConfig 中重要的方法 前言 HF 官网API 本文主要从官网AP…