将函数模板作为拷贝构造函数

news2024/11/29 0:50:12

目录

前言

一.认识pair

二.创建一个mypair对象

二.用mypair对象去初始化另一个mypair对象

三.全局的函数模版make_pair

四.map中的insert函数

五.验证 


​​​​​​​前言

当一个类的成员变量有自定义类型时,我们可以考虑将构造函数设为模板,这样会带来不少便利。便利之处在哪呢?看完本文就明白了。

一.认识pair

pair的介绍

pair是C++标准库里的一个类模板,本文将会仿照pair,以自己实现的mypair为例来说明将函数模板作为拷贝构造函数的好处。

二.创建一个mypair对象

#include <string>
template<class first_type, class second_type>
struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}

	first_type _first;
	second_type _second;
};

int main()
{
    mypair<string, string> m1;
    return 0;
}

如上,调用默认构造函数创建了一个mypair<string, string>对象,但这并不能使得我们满足,我们想要根据自己的想法来初始化_first和_second。于是,增加一个构造函数:

#include <string>
template<class first_type, class second_type>
struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}

    mypair(const first_type& first, const second_type& second)
		:_first(first)
		,_second(second)
	{}

	first_type _first;
	second_type _second;
};

int main()
{
    string s1 = ”left“;
    string s2 = "左边";
    mypair<string, string> m1(s1, s2);
    
    return 0;
}

可以按照自己的想法初始化mypair<string, string>对象了,但是这样有点麻烦啊,还要先创建两个string对象,有没有更简便的写法呢?

当然可以使用匿名对象:

mypair<string, string> m1(string(“left"), string("左边"));

但更简洁的写法是这样:

mypair<string, string> m1("左边", "left“);

 为什么可以这么写?因为传入的两个实参类型都是const char*, 而形参类型却是string的引用,string和const char*不匹配,所有这里会发生隐式类型转换,中间生成一个临时对象。正是因为const char*类型的变量能够拷贝构造string对象,这里的隐式类型转换才能顺利完成,所以实际上形参引用的是用const char* 拷贝构造的临时对象

二.用mypair对象去初始化另一个mypair对象

template<class first_type, class second_type>
struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}

	mypair(const first_type& first, const second_type& second)
		:_first(first)
		,_second(second)
	{}

	mypair(const mypair<first_type, second_type>& pr)
		:_first(pr._first)
		,_second(pr._second)
	{
		cout << "mypair的拷贝构造或普通构造" << endl;
	}

	first_type _first;
	second_type _second;
};

int main()
{
    mypair<const string, string> m1("left", "左边");
    mypair<string, string> m2("right", "右边");
    mypair<const string, string> m3(m1);//用m1拷贝构造m3
    //mypair<const string, string> m3(m2);  类型不匹配,编译报错
    return 0;
}

只需在pair中添加一个拷贝构造即可,但是你会这样的拷贝构造太有局限性了,要求实参与形参的类型严格匹配。例如我有一个pair<string, string>对象,现在我想用它拷贝构造一个对象,并要求第一个成员变量不能更改,所以将第一个模版参数设为const string。但遗憾的是,这是不允许的,因为pair<string,const string>和pair<string, string>是两个不同的类型。

怎么解决这个问题呢?答案是使用函数模版

template<class first_type, class second_type>
struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}
	
	mypair(const first_type& first, const second_type& second)
		:_first(first)
		,_second(second)
	{}

	template<class T1, class T2>
	mypair(const mypair<T1, T2>& pr)
		:_first(pr._first)
		,_second(pr._second)
	{
		cout << "mypair的拷贝构造或普通构造" << endl;
	}

	first_type _first;
	second_type _second;
};

int main()
{
    mypair<string, string> m1("right", "右边");
    mypair<const string, string> m2(m1);
    return 0;
}

将拷贝构造函数设为模版,当你给它传传实参时,自动推演形参的模版参数,例如你传的是pair<string, string>对象,那么T1推演成string,T2推演成string,因为string能够拷贝构造const string,所以没问题。

甚至这样做都是允许的:

int main()
{
    mypair<const string, string> m1(mypair<const char*, const char*>("left","左边"));
    return 0;
} 

这样能成功的原因是什么?因为const char*能初始化const string和string,这得多亏于string多样的构造函数。

小结:函数模版作为拷贝构造函数的优点在于,不必要求实参和被初始化的对象类型完全匹配,只需保证实参的模版参数类型能够用于初始化对象的成员变量即可。若实参类型和对象类型完全匹配,则生成的模版函数为拷贝构造函数,若不匹配,严格来说它只是一个普通构造函数。

三.全局的函数模版make_pair

 

struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}
	
	mypair(const first_type& first, const second_type& second)
		:_first(first)
		,_second(second)
	{}

	template<class T1, class T2>
	mypair(const mypair<T1, T2>& pr)
		:_first(pr._first)
		,_second(pr._second)
	{
		cout << "mypair的拷贝构造或普通构造" << endl;
	}

	first_type _first;
	second_type _second;
};

template<class T1, class T2>
mypair<T1, T2> my_make_pair(T1 x, T2 y)
{
	return mypair<T1, T2>(x, y);
}

int main()
{
    mypair<const string, string> m1(my_make_pair("left","左边"));
    mypair<const string, string> m2(mypair<const char*, const char*>("left","左边"))
}

仔细对比main函数中的两条语句,你会发现它们功能是一样的,但明显第一句更简洁。因为make_pair函数会帮我们自动推演pair的模版参数,不需要我们自己显式地写出来了。

四.map中的insert函数

如图,这是map的insert函数的声明,我们来关注它的参数。value_type是typedef过的,它其实是一个pair

typedef pair<const first_type, second_type> value_type; 
int main()
{
	map<string, string> dict;
	dict.insert(make_pair("sort", "排序"));
	return 0;
}

有了前面的介绍,我们就能理解这里的用法了。

首先dict调用insert函数,形参类型为const pair<const string, string>&,而make_pair的返回值类型为pair<const char*, const char*>,由于pair<const string, string>和pair<const char*, const char*>类型不匹配,所以要发生隐式类型转换,中间生成一个临时变量。这里为什么能隐式类型转换?这得得益于pair拷贝构造函数的巧妙设计,const char*能初始化const string和string,所以没问题。

五.验证 

template<class first_type, class second_type>
struct mypair
{
	mypair()
		:_first(first_type())
		,_second(second_type())
	{}
	
	mypair(const first_type& first, const second_type& second)
		:_first(first)
		,_second(second)
	{}

	template<class T1, class T2>
	mypair(const mypair<T1, T2>& pr)
		:_first(pr._first)
		,_second(pr._second)
	{
		cout << "mypair的拷贝构造或普通构造" << endl;
	}

	first_type _first;
	second_type _second;
};

template<class T1, class T2>
mypair<T1, T2> my_make_pair(T1 x, T2 y)
{
	return mypair<T1, T2>(x, y);
}

void func(const mypair<const string, string> s)
{
	cout << "func调用" << endl;
}

int main()
{
	cout << "类型完全匹配,不会发生隐式类型转换:" << endl;
	mypair<const string, string> m1("left", "左边");
	func(m1);
	cout << "--------------------------------------------" << endl;
	cout << "类型不匹配,发生隐式类型转换,调用mypair的拷贝构造函数,生成临时对象:" << endl;
	func(my_make_pair("left", "左边"));
	return 0;
}

 

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

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

相关文章

北斗卫星显身手,铁路作业人员安全防护再升级

北斗卫星显身手&#xff01;铁路作业人员安全防护再升级 在铁轨上忙碌的铁路作业人员&#xff0c;承载着运输与交通的重任&#xff0c;他们的辛勤付出为我们的生活提供了便利。然而&#xff0c;背后也隐藏着一系列的安全隐患和风险。为了确保铁路作业人员的安全&#xff0c;保障…

【实践篇】一次Paas化热部署实践分享 | 京东云技术团队

前言 本文是早些年&#xff0c;Paas化刚刚提出不久时&#xff0c;基于部门内第一次Paas化热部署落地经验所写&#xff0c;主要内容是如何构建一些热部署代码以及一些避雷经验。 一、设计-领域模型设计 1.首先&#xff0c;确定领域服务所属的领域 2.其次&#xff0c;确定垂直…

图解Linux内核进程调度系统

目录 1.进程调度系统 2.调度类 3.调度策略 4.调度实体 5.调度器 6.CPU运行队列 1.进程调度系统 Linux进程调度是操作系统内核中的一个重要组成部分&#xff0c;它负责决定哪个进程可以在CPU上运行。 进程调度的目标是合理分配CPU资源&#xff0c;提高系统的整体运行效率…

Java Web 学习笔记(二) —— JDBC

目录 1 JDBC 概述2 JDBC 快速入门3 JDBC API 详解3.1 DriverManager3.2 Connection3.3 Statement3.4 ResultSet3.5 PreparedStatement3.5.1 代码模拟 SQL 注入3.5.2 PreparedStatement 的使用3.5.3 PreparedStatement 原理 4 数据库连接池4.1 数据库连接池概述4.2 数据库连接池…

通讯网关软件034——利用CommGate X2ODBC实现Modbus RTU数据转储ODBC

本文介绍利用CommGate X2ODBC实现从Modbus RTU设备读取数据并转储至ODBC数据源。CommGate X2ODBC是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;实现从Modbus RTU设备读取数据并转储至ODBC…

性价比最高的护眼台灯是哪一款?盘点五款最具性价比的护眼台灯

现在的孩子&#xff0c;不是以往的孩子那么的无忧无虑&#xff0c;他们要考虑的是学习的成绩&#xff0c;所以很多孩子为了能在父母面前能得到夸奖&#xff0c;就努力的学习&#xff0c;那么台灯就不可缺少&#xff0c;但是如今市场上的台灯太多了&#xff0c;如果你购买的台灯…

HTTParty库

HTTParty是一个流行的Ruby库&#xff0c;用于简化HTTP请求和处理响应。它提供了一个简单的接口&#xff0c;可以轻松地发送HTTP请求&#xff0c;并处理返回的数据。 使用HTTParty&#xff0c;你可以&#xff1a; 发送GET、POST、PUT、DELETE等不同类型的HTTP请求。 设置请求头…

二、GRE VPN

GRE VPN 1、GRE介绍2、GRE基本原理3、GRE报文格式4、报文在GRE中传输过程5、价值6、Keepalive检测7、GRE应用8、配置GRE隧道8.1、配置绑定GRE协议的接口8.2、配置Tunnel接口8.3、配置Tunnel路由 9、GRE配置举例9.1、GRE静态路由示例9.1.1、路由器运行动态路由协议实现互通9.1.2…

STM32-HAL库08-TIM的输出比较模式(输出PWM的另一种方式)

STM32-HAL库08-TIM的输出比较模式&#xff08;输出PWM的另一种方式&#xff09; 一、所用材料&#xff1a; STM32F103C6T6最小系统板 STM32CUBEMX&#xff08;HAL库软件&#xff09; MDK5 示波器或者逻辑分析仪 二、所学内容&#xff1a; 通过定时器TIM的输出比较模式得到预…

分析外贸SEO推广流程?网站谷歌SEO优化方法?

外贸SEO推广详细教程&#xff1f;外贸企业站如何做谷歌SEO推广&#xff1f; 外贸SEO推广是国际贸易领域中的一项重要战略&#xff0c;通过优化网站内容和结构&#xff0c;提高搜索引擎排名&#xff0c;从而增加在线可见性&#xff0c;吸引更多国际客户。顺风船将深入分析外贸S…

可回馈式直流电子负载在光伏储能行业的应用

可回馈式直流电子负载在光伏储能行业的应用非常广泛&#xff0c;光伏储能系统主要由光伏阵列、逆变器和储能电池组成直流电子负载作为一个重要的测试设备&#xff0c;可以对光伏储能系统进行性能评估和负载模拟。可回馈式直流电子负载可以用于光伏阵列的性能评估&#xff0c;通…

【Proteus仿真】【Arduino单片机】RGB彩灯

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用WS2812 RGB彩灯等。 主要功能&#xff1a; 系统运行后&#xff0c;RGB彩灯花样显示。 二、软件设计 /* 作者&#xff1a;嗨小易&#xff08;…

【WIFI】关于MTK的射频参数文件CFG_WIFI_Default.h介绍

代码路径: vendor/mediatek/proprietary/custom/<project-name>/cgen/cfgdefault/CFG_WIFI_Default.h 先看下面这张图片,这是修改了国家码 2.4Ghz 5Ghz的配置参数 简单举例: 修改了国家码US改了那2个参数,可以看到一个改了0x55代表U,一个改了0x53代表S 加起…

Elasticsearch 8.X 如何生成 TB 级的测试数据 ?

1、实战问题 我只想插入大量的测试数据&#xff0c;不是想测试性能&#xff0c;有没有自动办法生成TB级别的测试数据&#xff1f;有工具&#xff1f;还是说有测试数据集之类的东西&#xff1f;——问题来源于 Elasticsearch 中文社区https://elasticsearch.cn/question/13129 2…

2023年11月实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

JVS低代码表单引擎助你打造高效表单设计流程

在日常的设计表单过程中&#xff0c;常常会有需要录入一大段文字的场景&#xff0c;例如评论、留言、产品介绍、内容说明等场景&#xff0c;那么简单的文本框组件就不满足了&#xff0c;这里JVS提供了 两种描述类型的组件&#xff0c;多行文本框和富文本组件&#xff0c;如下图…

ChatGPT 实际上是如何工作的?

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; ChatGPT 操作的两个主要阶段 我们再用谷歌来打个比方。当你要求谷歌查找某些内容时&#xff0c;你可能知道它不会——在你提出要求的那一刻——出去搜索整个网络来寻找答案。相反&#xff0c;谷歌会在其数…

Django实战项目-学习任务系统-发送邮件通知

接着上期代码内容&#xff0c;继续完善优化系统功能。 本次增加发送邮件通知功能&#xff0c;学习任务系统发布的任务&#xff0c;需要及时通知到学生用户知晓。 由于目前智能手机普及&#xff0c;人人都离不开手机&#xff0c;所以手机端接收通知信息更加及时有效。 其中微信…

[开源]企业级在线办公系统,基于实时音视频完成在线视频会议功能

一、开源项目简介 企业级在线办公系统 本项目使用了SpringBootMybatisSpringMVC框架&#xff0c;技术功能点应用了WebSocket、Redis、Activiti7工作流引擎&#xff0c; 基于TRTC腾讯实时音视频完成在线视频会议功能。 二、开源协议 使用GPL-3.0开源协议 三、界面展示 部分…

git根据commitid创建tag标签

1.首先&#xff0c;创建一个新的标签。你可以使用以下命令创建一个轻量级标签&#xff08;lightweight tag&#xff09;&#xff1a; 针对当前标签而言,也就是你所在的当前分支而言 git tag <tag_name>2.如果你想创建一个带注释的标签 针对当前标签而言,也就是你所在的…