C plus plus ——【模板应用】

news2024/12/23 10:46:25

系列文章目录

C plus plus ——【模板应用】


文章目录

  • 系列文章目录
  • 前言
  • 一、函数模板
    • 1.1、函数模板的定义
    • 1.2、函数模板的作用
    • 1.3、重载函数模板
  • 二、类模板
    • 2.1、类模板的定义与声明
    • 2.2、简单类模板
    • 2.3、默认模板参数
    • 2.4、为具体类型的参数提供默认值
  • 三、总结


前言

模板是C++语言的高级特性,分为函数模板和类模板两大类。模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现大大方便了大规模软件开发。


一、函数模板

函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。

1.1、函数模板的定义

函数模板定义的一般形式如下:

template <类型形式参数表>
返回类型  函数名(形式参数表)
{
	//函数体
}

template 为关键字,表示定义一个模板;尖括号“<>” 表示模板参数,模板参数主要有两种,一种是模型类型参数,另一种是模板非类型参数。模板类型参数使用关键字class 或 typedef 开始,其后是一个用户定义的合法标识符。模板非类型参数与普通参数定义相同,通常为一个常数。
可以将声明函数模板分成template部分和函数名部分。例如:

template<class T>
void fun(T t)
{
	//函数实现
}

定义一个求和的函数模板,例如:

template <class type>     //定义一个模板类型
type Sum(type xvar,type yvar)  //定义函数模板
{
	return xvar+yvar;
}

在定义完函数模板之后,需要在程序中调用函数模板。下面的代码演示了Sum函数的调用。

int  iret = Sum(10,20);          //实现两个整数的相加
double dret = Sum(10.5,20.5);    //实现两个实数的相加

如果采用如下的形式调用Sum函数模板,将会出现错误。

int  iret  = Sum(10.5,20);        //错误的调用
double dret = Sum(10,20.5);       //错误的调用

上述代码中为函数模板传递了两个类型不同的参数,编译器产生了歧义。如果用户在调用函数模块时显示标识模板类型,就不会出现错误了。例如:

int iret = Sum<int>(10.5,20);   //正确地调用函数模板
double dret = Sum<double>(10,20.5)  //正确地调用函数模板

用函数模板生成实际可执行的函数又称为模板函数。函数模板与模板函数不是一个概念。从本质上讲,函数模板是一个“框架”,它不是真正可以编译生成代码的程序,而模板函数是把函数模板中的类型参数实例化后生成的函数,它和普通函数本质是相同的,可以生成可执行代码。

1.2、函数模板的作用

假设求两个函数之中最大者,如果想求整型数和实型数需要定义以下两个函数:

int max(int a,int b)
{
	return a>b?a:b;  //返回最大值
}
float max(float a,float b)
{
	return a>b?a:b;  //返回最大值
}

可以使用函数模板以及#define 宏定义实现一个max 函数来完成既求整型数之间最大者又求实型数之间的最大者。
#define 宏定义可以在预编译期对代码进行替换。例如:

#define max(a,b) ((a)>(b)?(a):(b))

上述代码可以求整型数最大值和实型数最大值。但宏定义#define 只是进行简单替换,它无法对类型进行检查,有时计算结果可能不是预计的。例如:

#include <iostream>
#include <iomanip>
using namespace std;
#define max(a,b)((a)>(b)?(a):(b))
int main(int argc,char* argv[])
{
	int m=0,n=0;
	cout<<max(m,++n)<<endl;
	cout<<m<<setw(2)<<endl;  
	return 0;
}

程序运行结果如下:
在这里插入图片描述
程序运行的预期结果应该是1和0,但是实际是2和0,这是因为宏替换之后“++n”被执行了两次,因此n的值是2不是1。
宏是预编译指令,很难调试,无法单步进入宏的代码中。模板函数和#define 宏定义相似,但模板函数是用模板实例化得到的函数,它与普通函数没有本质区别,可以重载模板函数。
使用模板求最大值的代码如下:

template <class Type>
type max(Type a,Type b)
{
	if(a>b)
		return a;
	else
		return b;	
}

调用模板函数max可以正确计算整型数和实型数的最大值。例如:

cout<<"最大值:"<<max(10,1)<<endl;
cout<<"最大值:"<<max(200.05,100.4)<<endl;

使用数组作为模板参数。

#include <iostream>
using namespace std;
template <class type,int len>  //定义一个模板类型
type Max(type array[len])
{
	type ret = array[0];   //定义一个变量
	for(int i=1; i<len;i++)  //遍历数组元素
	{
		ret = (ret>array[i])?ret:array[i]; //比较数组元素大小
	}
	return ret;       //返回最大值
}
int main(int argc,char* argv[])
{
	int array[5] = {1,2,3,4,5};   //定义一个整型数组
	int iret = Max<int,5>(array);  //调用函数模板Max
	cout<<iret<<endl;
	double dest[3] = {10.5,11.2,9.8}; //定义实数数组
	double dret = Max<double,3>(dest); //调用函数模板
	cout<<dret<<endl;
}

程序运行结果如下图所示:
在这里插入图片描述
程序中定义一个函数模板Max,用来求数组中元素的最大值,其中模板参数使用模板类型参数type和模板非类型参数len,参数type声明了数组中的元素类型,参数len声明了数组中的元素个数,给定数组元素后,程序将数组中的最大值输出。

1.3、重载函数模板

整型数和实型数编译器可以直接进行比较,所以使用函数模板后也可以直接进行比较。重载函数模板可以用来使字符指针指向的字符串进行比较。

#include <iostream>
#include <string>
using namespace std;
template <class Type>
Type Tmin(Type a,Type b)   //定义函数模板
{
	if(a<b)
		return a;
	else
		return b;
}
char *Tmin(char *a,char *b)     //重载函数模板
{
	if(strcmp(a,b))
		return b;
	else
		return a;	
}
int main(int argc ,char* argv[])
{
	cout<<"Minimum:"<<min(10,1)<<endl;
	cout<<"Minimum:"<<min('a','b')<<endl;
	cout<<"Minimum:"<<min("hi","mr")<<endl;
	return 0;
}

程序运行结果如下图所示:
在这里插入图片描述
程序在重载的函数模板Tmin的实现,使用strcmp库函数来完成字符串的比较,此时使用Tmin函数可以比较整型数据、实型数据、字符数据和字符串数据。

二、类模板

使用template关键字不但可以定义函数模板,也可以定义类模板。类模板代表一族类,是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的参数或返回值可以取任意数据类型。类模板可以说是用类生成类,减少了类的定义数量。

2.1、类模板的定义与声明

类模板的一般定义形式如下:

template <类型形式参数表>
class   类模板名
{
	...//类模板体
};

类模板成员函数的定义如下:

template   <类型形式参数表>
返回类型   类模板名 <类型名表>::成员函数名(形式参数列表)
{
	... //函数体
}

template 是关键字,类型形式参数表与函数模板定义相同。类模板的成员函数定义时的类模板名与类模板定义时要一致,类模板不是一个真实的类,需要重新生成类,生成类的形式如下:

类模板名<类型实在参数表>

用新生成的类定义对象的形式如下:

类模板名<类型实在参数表>  对象名

其中类型实在参数表应与该类模板中的类型形式参数表匹配。用类模板生成的类称为模板类。类模板和模板类不是同一个概念,类模板是模板的定义,不是真实的类,定义中要用到类型参数;模板类本质上与普通的类相同,它是类模板的类型参数实例化之后得到的类。
定义一个容器的类模板,代码如下:

template <class Type>
class Container
{
	Type tltem;
	public:
	Container()
	{
	
	};
	void begin(const Type&tNew);
	void end(const Type&tNew);
	void insert(const Type&tNew);
	void empty(const Type&tNew);
};

和普通类一样,需要对类模板成员函数进行定义,代码如下:

void Container<type>::begin(const Type&tNew)     //容器的第一个元素
{
	tltem = tNew; 
}
void Container<type>::end(const Type&tNew)  //容器的最后一个元素
{
	tltem = tNew;
}
void Container<type>::empty(const Type&tNew)  //清空容器
{
	tltem = tNew;
}

将模板类的参数设置为整型,然后用模板类声明对象,代码如下:

Container<int> myContainer;      //声明Container<int>类对象

声明对象后,就可以调用类成员函数,代码如下:

int i = 10;
myContainer.insert(i);

在类模板定义中,类型形式参数表中的参数也可以是其他类模板。例如:

template<template<class A> class B>
class CBase
{
private:
	B<int> m_n;
}

类模板也可以进行继承。例如:

template<class T>
class CDerived public T
{
public:
	CDrived();	
};
template<class T>
CDerived<T>::CDerived:T()
{
	cout<<""<<endl;
}
void main()
{
	CDerived<CBase1>D1;
}

T是一个类,CDerived继承自该类,CDerived 可以对类T进行扩展。

2.2、简单类模板

类模板中的类型形式参数表可以在执行时指定,也可以在定义类模板时指定。简单类模板如下:
简单类模板。

#include<iostream>
using namespace std;

template<class T1 ,class T2>
class MyTemplate
{
	T1  t1;
	T2  t2;
public:
		MyTemplate(T1 tt1,T2 tt2)
		{
			t1 = tt1;
			t2 = tt2;
		}
		void display()
		{
			cout<<t1<<' '<<t2<<endl;
		}
};
int  main()
{
	int a=123;
	double b=3.1415;
    MyTemplate<int ,double>mt1(a,b);
    MyTemplate<int,int > mt2(a,b);
	mt1.display();
	mt2.display();
	return 0;
	
}

程序运行结果如下图所示:
在这里插入图片描述

2.3、默认模板参数

默认模板参数是类模板中由默认的数据类型作参数,在模板定义时还可以为默认的数据类型声明变量,并且为变量赋值。为具体类型的参数提供默认值实例如下:

#include<iostream>
using namespace std;
template<class T1,class T2 = int>
class MyTemplate
{
	T1 t1;
	T2 t2;
	public:
		MyTemplate(T1 tt1,T2 tt2)
		{
			t1 = tt1;
			t2 = tt2;
		}
		void display()
		{
			cout<<t1<<' '<<t2<<endl;
		}
};

int main(int argc ,char* argv[])
{
	int a = 123;
	double b = 3.1415;
	MyTemplate<int ,double> mt1(a,b);
	MyTemplate<int> mt2(a,b);
	mt1.display();
	mt2.display();
	return 0;
}

程序运行结果如下图所示:
在这里插入图片描述

2.4、为具体类型的参数提供默认值

默认模板参数是类模板中由默认的数据类型作参数,在模板定义时还可以为默认的数据类型声明变量,并且为变量赋值。

#include<iostream>
using namespace std;
template<class T1,class T2,int num = 10>
class MyTemplate
{
	T1 t1;
	T2 t2;
	public:
		MyTemplate(T1 tt1,T2 tt2)
		{
			t1 = tt1+num,t2 = tt2+num;
		}
		void display()
		{
			cout<<t1<<' '<<t2<<endl;
		}
};
int main(int argc ,char* argv[])
{
	int a = 123;
	double b = 3.1415;
	MyTemplate<int ,double> mt1(a,b);
	MyTemplate<int ,double,100> mt2(a,b);
	mt1.display();
	mt2.display();
	return 0;
}

程序运行结果如下图所示:
在这里插入图片描述

三、总结

模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现大大方便了大规模软件开发。

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

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

相关文章

Selenium Python教程第4章

4. 查找元素 在一个页面中有很多不同的策略可以定位一个元素。在你的项目中&#xff0c; 你可以选择最合适的方法去查找元素。Selenium提供了下列的方法给你: find_element_by_id find_element_by_name find_element_by_xpath find_element_by_link_text find_element_by_par…

自己制作智能语音机器人(基于jetson nano)

1 简介 如上图&#xff0c;主要采用jetson上编写python代码实现&#xff0c;支持离线语音唤醒、在线语音识别、大模型智能文档、在线语音合成。 所需硬件如下&#xff1a; jetson nano&#xff1a;linux科大讯飞麦克风硬件&#xff1a;AIUI R818麦克阵列开发套件6麦阵列&#…

华为全栈自主数据库GaussDB正式面向全球服务

一、前言 在6月7日举行的华为全球智慧金融峰会2023上&#xff0c;华为发布新一代分布式数据库GaussDB&#xff0c;并正式向全球客户提供服务。据介绍&#xff0c;GaussDB实现了核心代码100%自主研发&#xff0c;是国内当前唯一做到软硬协同、全栈自主的国产数据库。 可谓是里…

继承类的方法

1 问题 定义一个父类&#xff0c;用子类去继承父类所拥有的方法、定义属性&#xff0c;然后使用测试文件实现子类输出父类的方法信息&#xff0c;属性等。 2 方法 2.1 定义一个名为Person的父类&#xff1a; 2.2 定义一个名为Student的子类&#xff0c;并令其继承父类&#xff…

【PXIE301-211】基于PXIE总线架构的16路并行LVDS采集、1路光纤数据处理平台

PXIE301-211是一款基于PXIE总线架构的16路并行LVDS数据采集、1路光纤收发处理平台&#xff0c;该板卡采用Xilinx的高性能Kintex 7系列FPGA XC7K325T作为实时处理器&#xff0c;实现各个接口之间的互联。板载1组64位的DDR3 SDRAM用作数据缓存。板卡具有1个FMC&#xff08;HPC&am…

20道常考Python面试题大总结,让你轻松拿下大厂offer

关于Python的面试经验 一般来说&#xff0c;面试官会根据求职者在简历中填写的技术及相关细节来出面试题。 一位拿了大厂技术岗Special Offer的网友分享了他总结的面试经验。当时&#xff0c;面试官根据他在简历中所写的技术&#xff0c;面试题出的范围大致如下&#xff1a; …

国际化语言项目

基本概念 1、使用QString对象表示所有用户可见的文本。由于QString内部使用Unicode编码实现&#xff0c;所以它可以用 于表示所有需要向用户呈现的文本。当然&#xff0c;对于仅程序员可见的文本并不需要都变为QString对象&#xff0c;可利 用Qt提供的QCString或原始的“char …

VisualGLM训练缺失latest文件问题解决

清华已经公布了VisualGLM 模型&#xff0c;图像预测也取得了比较好的效果&#xff0c;但是我在调试微调的过程遇到不少问题&#xff0c;这里记录一下缺失latest问题解决&#xff08;ValueError: could not find the metadata file ../latest, please&#xff09; 修正后的代码可…

PyEMD算法解析

算法背景 经验模态分解&#xff08;Empirical Mode Decomposition&#xff0c;缩写EMD&#xff09;是由黄锷&#xff08;N. E. Huang&#xff09;在美国国家宇航局与其他人于1998年创造性地提出的一种新型自适应信号时频处理方法&#xff0c;特别适用于非线性非平稳信号的分析处…

易基因|一种全新的检测DNA羟甲基化的技术:ACE-Seq

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑做组学科研服务的易基因。今天给大家介绍一种全新的检测DNA羟甲基化的技术&#xff1a;APOBEC-coupled epigenetic sequencing&#xff0c;简称【ACE-seq】。 前言 DNA序列中胞嘧啶&#xff08;C&#xff09;5’ 碳…

sed命令对文件内的指定字符串进行替换

目录 一、创建一个txt文件 二、替换每行第一个huawei为apple&#xff0c;第三个“/”后&#xff0c;不加参数就是只替换第一个 三、替换每行所有的xiaomi为iphone&#xff0c;第三个“/”后&#xff0c;加参数g就是替换所有 四、替换每行第二个redmi为potato&#xff0c;第…

ubutun22.04使用deb包安装mysql8.0.33

下载:https://dev.mysql.com/downloads/mysql/ 下载完毕,在ubuntu服务器解包。 安装使用dpkg命令,依次执行如下: sudo dpkg -i mysql-common_8.0.33-1ubuntu22.04_amd64.deb sudo dpkg -i mysql-community-client-plugins_8.0.33-1ubuntu22.04_amd64.deb sudo dpk…

云原生|秒懂云原生容灾备份实践

作者&#xff1a;刘健 后端开发工程师 目录 一、需备份的数据 二、在云航项目中使用 三、备份任务说明 一、需备份的数据 kubernetes在运行中&#xff0c;通常会产生两类数据&#xff1a; kubernetes集群资源对象数据。 容器运行时产生的数据。 针对cloudUp项目而言&am…

淘宝商品信息存入数据库

python 爬虫程序&#xff1a; #京东.pyimport json import pprint import re import requests # name_turnover {} url "https://s.taobao.com/search?data-keys&data-value88&ajaxtrue&_ksTS1686118766568_2290&callbackjsonp2291&ieutf8&in…

用AI写出的高考作文!

今天是6月7日&#xff0c;又到了每一年高考的日子。小灰自己参加高考是在2004年&#xff0c;距离现在已经将近20年&#xff0c;现在回想起来&#xff0c;真的是恍如隔世。 今天高考语文的作文题是什么呢&#xff1f; 全国甲卷的题目是&#xff1a;人技术时间 人们因技术发展得以…

centos7 部署 Redis

从源安装Redis 一、安装Redis1.1 下载源文件1.2 编译源文件1.2.1 解压文件1.2.2 编译Redis 1.2.3 安装Redis1.2.4 启动 Redis 二、Redis设置2.1 缓存设置2.2 redis 环境优化2.3 安全设置 一、安装Redis 1.1 下载源文件 使用下列命令获取最新版的稳定Redis wget https://down…

Live800:智能客服有哪些未来发展趋势?

智能客服&#xff0c;也称智能问答系统&#xff0c;是一种利用机器学习、自然语言处理等技术实现自主询问、自主应答、自主维护的自动化系统。它们可以通过文字形式&#xff0c;为用户提供个性化、一对一的服务&#xff0c;避免了人工客服的人力成本和等待时间。 未来&#xff…

【Protobuf速成指南】enum类型的使用

文章目录 2.1枚举类型一、如何定义枚举类型&#xff1f;二、语法规范三、重定义问题四、enum类型相关函数五、Contact 2.1 改写六、总结 2.1枚举类型 本系列文章将通过对通讯录项目的不断完善&#xff0c;带大家由浅入深的学习Protobuf的使用。这是Contacts的2.1版本&#xff0…

【IMX6ULL驱动开发学习】02.IMX6ULL烧写Linux系统

由于我买的是正点原子的IMX6ULL阿尔法开发板&#xff0c;但是我是看韦东山老师视频学习的驱动 所以这里我烧录的方法是按照韦东山老师的课程来的 这里给出烧写Linux系统用到的工具 链接&#xff1a;https://pan.baidu.com/s/1bD-xxn3K8xQAVkJSaJmTzQ 提取码&#xff1a;af6w …

操作系统1-操作系统的基本特征和主要功能

目录 1、操作系统的目标和作用 &#xff08;1&#xff09;操作系统的目标 &#xff08;2&#xff09;操作系统的作用 2、操作系统的发展过程 &#xff08;1&#xff09;未配置操作系统的计算机系统 &#xff08;2&#xff09;单道批处理系统(Simple Batch Processing Sys…