相关文章推荐
儒雅的针织衫  ·  CMakeLists中使用指定路径vcpkg ...·  10 月前    · 
绅士的花卷  ·  Visual Studio ...·  10 月前    · 
豪气的勺子  ·  编译错误:用户定义类型未定义(IUnknow ...·  1 年前    · 
阳刚的板凳  ·  postgresql - Rails: ...·  1 年前    · 
笑点低的猴子  ·  数据指标体系搭建实践_51CTO博客_数据指 ...·  1 年前    · 
Code  ›  C++模板详解 —— 函数模板与类模板-天翼云
https://www.ctyun.cn/zhishi/p-345182
温暖的遥控器
10 月前

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
查看全部活动
热门活动
  • 2024云享优惠·数智升级 NEW 爆款2核4G3M云服务器82.8元/年起
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 一键部署Llama3大模型学习机 0代码一键部署,预装最新主流大模型Llama3与StableDiffusion
  • 中小企业上云场景组合购 NEW 建站、域名等场景一站式购齐,组合购9元起!
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 云主机特惠 HOT 多款云主机新老同享,满足您的上云需求!
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城 进入云市场
办公协同
  • WPS云文档 EMM手机管家 智能商业平台 SSL证书 新域名服务 翼电子教室 翼智慧显示一体化解决方案 税务风控云 翼云智眼安消一体化解决方案 翼信息化运维服务 翼微信营销解决方案 翼视频云归档解决方案 云管家2.0 智慧工厂_生产流程管理解决方案 全栈混合云敏捷版(软件) 全栈混合云敏捷版(一体机)

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云技术合作伙伴
  • 天翼云OpenAPI中心 天翼云EasyCoding平台
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云培训认证
  • 天翼云学堂 天翼云市场商学院
天翼云服务合作伙伴
  • 天翼云MSP合作伙伴 天翼云集成商交付能力认证
天翼云合作计划
  • 央企云合作计划
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴 天翼云甄选商城合作伙伴
天翼云东升计划
  • 东升适配创新中心 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
资源与工具
  • 天翼云OpenAPI EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂 天翼云认证

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • OpenAPI中心 客户支持计划 专家技术服务

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云 天翼云4.0 天翼云APP 全球基础设施 分析师和白皮书 天翼云·创新直播间 2024智算云生态大会 2023云生态大会 2022云生态大会 天翼云中国行 支持与服务 了解天翼云
  • 站点切换
    • 中国站
  • 文档
  • 控制中心
  • 备案
  • 管理中心

C++模板详解 —— 函数模板与类模板

首页 知识中心 软件开发 文章详情页

C++模板详解 —— 函数模板与类模板

2024-04-03 09:24:07 阅读次数:15

c++

如果让你编写一个函数,用于两个数的交换。在C语言中,我们会用如下方法:

// 交换两个整型
void Swapi(int* p1, int* p2)
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
// 交换两个双精度浮点型
void Swapd(double* p1, double* p2)
	double tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;

 因为C语言不支持函数重载,所以用于交换不同类型变量的函数的函数名是不能相同的,并且传参形式必须是址传递,不能是值传递。

 而在学习了C++的函数重载和引用后,我们又会用如下方法实现两个数的交换:

// 交换两个整型
void Swap(int& x, int& y)
	int tmp = x;
	x = y;
	y = tmp;
// 交换两个双精度浮点型
void Swap(double& x, double& y)
	double tmp = x;
	x = y;
	y = tmp;

 C++的函数重载使得用于交换不同类型变量的函数可以拥有相同的函数名,并且传参使用引用传参,使得代码看起来不那么晦涩难懂。

但是,这种代码仍然存在它的不足之处:
 1、重载的多个函数仅仅只是类型不同,代码的复用率比较低,只要出现新的类型需要交换,就需要新增对应的重载函数。
 2、代码的可维护性比较低,其中一个重载函数出现错误可能意味着所有的重载函数都出现了错误。

 那我们能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成相应的代码呢?
C++模板详解 —— 函数模板与类模板
 就像做月饼的模子一样,我们放入不同颜色的材料,就能得到形状相同但颜色不同的月饼。
 如果在C++中,也能够存在这样一个模具,通过给这个模具填充不同颜色的材料(类型),从而得到形状相同但颜色不同的月饼(生成具体类型的代码),那将会大大减少代码的冗余。巧的是前人早已将树栽好,我们只需在此乘凉。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
C++模板详解 —— 函数模板与类模板

函数模板的概念

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

函数模板的格式

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

template<typename T>




    

void Swap(T& x, T& y)
	T tmp = x;
	x = y;
	y = tmp;

注意:typename是用来定义模板参数的关键字,也可以用class代替,但是不能用struct代替。

函数模板的原理

 那么函数模板的底层原理是什么呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。其本质就是将重复的工作交给了机器去完成。有人给出了论调:懒人创造世界!
 
马云:世界是懒人创造的
C++模板详解 —— 函数模板与类模板
懒不是傻懒,如果你想少干,就要想出懒的方法。要懒出风格,懒出境界。

 函数模板是一个蓝图,它本身并不是函数。是编译器产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
C++模板详解 —— 函数模板与类模板
 在编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如,当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然后产生一份专门处理int类型的代码,对于double类型也是如此。

函数模板的实例化

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

一、隐式实例化:让编译器根据实参推演模板参数的实际类型

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
	return x + y;
int main()
	int a = 10, b = 20;
	int c = Add(a, b); //编译器根据实参a和b推演出模板参数为int类型
	return 0;

特别注意:使用模板时,编译器一般不会进行类型转换操作。所以,以下代码将不能通过编译:

	int a = 10;
	double b = 1.1;
	int c = Add(a, b);

 因为在编译期间,编译器根据实参推演模板参数的实际类型时,根据实参a将T推演为int,根据实参b将T推演为double,但是模板参数列表中只有一个T,编译器无法确定此处应该将T确定为int还是double。
 此时,我们有两种处理方式,第一种就是我们在传参时将b强制转换为int类型,第二种就是使用下面说到的显示实例化。

二、显示实例化:在函数名后的<>中指定模板参数的实际类型

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
	return x + y;
int main()
	int a = 10;
	double b = 1.1;
	int c = Add<int>(a, b); //指定模板参数的实际类型为int
	return 0;

注意:使用显示实例化时,如果传入的参数类型与模板参数类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功,则编译器将会报错。

函数模板的匹配原则

一、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

#include <iostream>
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
	return x + y;
//通用类型加法的函数模板
template<typename T>
T Add(const T& x, const T& y)
	return x + y;
int main()
	int a = 10, b = 20;
	int c = Add(a, b); //调用非模板函数,编译器不需要实例化
	int d = Add<int>(a, b); //调用编译器实例化的Add函数
	return 0;

二、对于非模板函数和同名的函数模板,如果其他条件都相同,在调用时会优先调用非模板函数,而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么选择模板

#include <iostream>
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
	return x + y;
//通用类型加法的函数模板
template<typename T1, typename T2>
T1 Add(const T1& x, const T2& y)
	return x + y;
int main()
	int a = Add(10, 20); //与非模板函数完全匹配,不需要函数模板实例化
	int b = Add(2.2, 2); //函数模板可以生成更加匹配的版本,编译器会根据实参生成更加匹配的Add函数
	return 0;

三、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
	return x + y;
int main()
	int a = Add(2, 2.2); //模板函数不允许自动类型转换,不能通过编译
	return 0;

 因为模板函数不允许自动类型转换,所以不会将2自动转换为2.0,或是将2.2自动转换为2。

类模板的定义格式

template<class T1,class T2,…,class Tn>
class 类模板名
{
  //类内成员声明
};

template<class T>
class Score
public:
	void Print()
		cout << "数学:" << _Math << endl;
		cout << "语文:" << _Chinese << endl;
		cout << "英语:" << _English << endl;
private:
	T _Math;
	T _Chinese;
	T _English;

注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。

template<class T>
class Score
public:
	void Print();
private:
	T _Math;
	T _Chinese;
	T _English;
//类模板中的成员函数在类外定义,需要加模板参数列表
template<class T>
void Score<T>::Print()
	cout << "数学:" << _Math << endl;
	cout << "语文:" << _Chinese << endl;
	cout << "英语:" << _English << endl;




    

 除此之外,类模板不支持分离编译,即声明在xxx.h文件中,而定义却在xxx.cpp文件中。

类模板的实例化

 类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面根<>,然后将实例化的类型放在<>中即可。

    //Score不是真正的类,Score<int>和Score<double>才是真正的类
	Score<int> s1;
	Score<double> s2;

注意:类模板名字不是真正的类,而实例化的结果才是真正的类。

版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.csdn.net/chenlong_cxy/article/details/117629686,作者:2021dragon,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

上一篇: Python数据类型 ——— 元组

下一篇: 02_Vue 的基本代码

相关文章

2024-06-13 08:59:42

const那些事儿

常类型是指使用类型修饰符const说明的类型,是只读的(不能更新),这意味着需要在定义的时候就要赋初值。

2024-06-13 08:59:42
2024-06-13 08:59:42

程序清单 18.2 Mammal13.cpp 的单继承问题使用纯虚函数解决

程序清单 18.2 Mammal13.cpp 的单继承问题使用纯虚函数解决

2024-06-13 08:59:42
2024-06-13 08:59:42

c++入门经典学习笔记 17.1使用虚函数实现多态

c++入门经典学习笔记 17.1使用虚函数实现多态

2024-06-13 08:59:42
2024-06-13 08:59:42

c++单继承存在的问题:将基类指针转换成派生指针dynamic_cast运算符

c++单继承存在的问题:将基类指针转换成派生指针dynamic_cast运算符

2024-06-13 08:59:42
2024-06-13 08:59:42

c++运算符重载的一些理解

运算符重载类似于调用函数,对于用户定义的类,c++没有可以比较他们关系的运算符,所以就像定义函数那样来重载运算符。

2024-06-13 08:59:42
2024-06-13 08:59:42

c++抽象数据类型

shape是一种抽象数据类型(ADT),只为其派生类提供接口,如果试图实例化Shape对象,将很麻烦,也许应该使其不可能。

2024-06-13 08:59:42
2024-06-13 08:12:14

C++语句如何换行和C++中字符串太长如何换行

C++语句如何换行和C++中字符串太长如何换行

2024-06-13 08:12:14
2024-06-13 08:07:37

C/C++ realloc()函数解析

C/C++ realloc()函数解析

2024-06-13 08:07:37
2024-06-12 09:30:16

C#编程-94:迭代器Iterator简单实例_彭世瑜_新浪博客

C#编程-94:迭代器Iterator简单实例_彭世瑜_新浪博客

2024-06-12 09:30:16
leetcode 2024-06-12 09:30:16

0023 c/c++语言 pi的来历

0023 c/c++语言 pi的来历

2024-06-12 09:30:16
查看更多
推荐标签

作者介绍

天翼云小翼
天翼云用户

文章

21549

阅读量

2125547

查看更多

最新文章

程序清单 18.2 Mammal13.cpp 的单继承问题使用纯虚函数解决

2024-06-13 08:59:42

C++语句如何换行和C++中字符串太长如何换行

2024-06-13 08:12:14

C/C++ realloc()函数解析

2024-06-13 08:07:37

C#编程-94:迭代器Iterator简单实例_彭世瑜_新浪博客

2024-06-12 09:30:16

0023 c/c++语言 pi的来历

2024-06-12 09:30:16

C/C++获取当前路径、获取任意pid完整路径(readlink函数)

2024-06-11 08:17:06

查看更多

热门文章

Lambda函数

2023-02-08 10:33:56

QT中多线程的使用

2023-02-07 10:34:04

0030 简单的四则运算 c/c++

2023-03-21 10:39:47

C++虚函数知识点总结

2023-02-21 06:21:46

C++类模板

2023-02-08 10:33:56

(10)Qt对象模型

2023-02-13 07:55:59

查看更多

热门标签

python Python javascript spring linux SpringBoot springboot
查看更多

相关产品

弹性云主机

随时自助获取、弹性伸缩的云服务器资源

天翼云电脑(公众版)

便捷、安全、高效的云电脑服务

对象存储

高品质、低成本的云上存储服务

云硬盘

为云上计算资源提供持久性块存储

查看更多

随机文章

C++:转义符(10)

C++ 常用练习小例子

【C++】继承——切片、隐藏、默认成员函数、菱形

【C++】string类的模拟实现

C++11 ——— 右值引用和移动语义

C++线程池实现解析

  • 7*24小时售后
  • 无忧退款
  • 免费备案
  • 专家服务
售前咨询热线
400-810-9889转1
  • 天翼云APP
    天翼云APP
 
推荐文章
儒雅的针织衫  ·  CMakeLists中使用指定路径vcpkg和指定路径的三方库_cmakelists vcpkg-CSDN博客
10 月前
绅士的花卷  ·  Visual Studio 调试器中的符号/PDB 文件 | Microsoft Learn
10 月前
豪气的勺子  ·  编译错误:用户定义类型未定义(IUnknown)-CSDN博客
1 年前
阳刚的板凳  ·  postgresql - Rails: PG::UndefinedTable: ERROR: relation "..." does not exist - Stack Overflow
1 年前
笑点低的猴子  ·  数据指标体系搭建实践_51CTO博客_数据指标体系搭建
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号