首页 > 编程语言 >【C++提高篇】—— C++泛型编程之模板基本语法和使用的详解

【C++提高篇】—— C++泛型编程之模板基本语法和使用的详解

时间:2025-01-20 21:27:49浏览次数:3  
标签:函数 示例 int 数据类型 C++ 类型 泛型 模板

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

C++中的另一种编程思想称为泛型编程,主要利用模板和标准模板库(STL)。泛型编程通过编写与数据类型无关的代码,提高了代码的复用性和灵活性。STL提供了一套丰富的容器、算法和迭代器,使开发者可以高效地处理各种数据结构和算法。本章节将系统介绍泛型编程的概念、模板的使用方法以及STL的基本组件。

一、模板的概念

模板:模板就是建立通用的模具,大大提高复用性
模板的特点
a. 模板不可以直接使用,它只是一个框架
b. 模板的通用并不是万能的

二、函数模板

2.1 函数模板的使用

语法
template< typename T>
函数声明或定义
解释
template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母

示例
传统的实现:对于不同的数据类型的交换函数,要分开每个都要写一遍实现:

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

使用函数模板:对于操作一样的函数,写一次实现即可

template<typename T>
void mySwap(T &a,T &b) {    //传入引用:交换实参
		T temp = a;
		a = b;
		b = temp;
}
//使用
int main()
{
	int a = 10;  
	int b = 20;
	mySwap(a,b);   //利用模板实现交换//1、自动类型推导
	// mySwap<int>(a,b);  //2、显示指定类型
	cout<< "a=" << a << "b=" << b <<endl;
	system("pause");
	return 0;
}

总结
函数模板定义后,有两种使用方式:
a. 自动类型推导

mySwap(a,b);

b. 显示指定类型

mySwap<int>(a,b);
mySwap<double >(a,b);

2.2 函数模板注意事项

(1) 注意事项一:使用自动类型推导调用的方法
自动类型推导,必须推导出一致的数据类型T, 才可以使用
示例

int main()
{
	int a = 10;
	int b = 20;
	char c = 'c';
	mySwap(a,b);   //正确,可以推导出一致的T
	//mySwap(a,c);//错误,a和c数据类型不同,推导不出一致的T类型
	cout<< "a=" << a << "b=" << b <<endl;
	system("pause");
	return 0;
}

(2) 注意事项二
使用模板时必须要确定出T的数据类型,才可以使用
示例

template<classT>
void func(){
cout<< "func调用" <<endl;
}
int main()
{
	//func();//错误,模板不能独立使用,必须确定出T的类型
	func<int>();//利用显示指定类型的方式,给T一个类型,才可以使用该模板}
	system("pause");
	return 0;
}

2.3 普通函数与函数模板的区别

区别
a. 普通函数调用时可以发生自动类型转换(隐式类型转换)
b. 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
c. 如果利用显示指定类型的方式,可以发生隐式类型转换
示例

void myPrint(int a,int b){
	cout<< "调用的普通函数a + b:" << a + b <<endl;
}
template<typename T>
void myPrint(T a, T b){
	cout<< "调用的模板a + b:" << a + b <endl;
}
void test01(){
	int a = 10;
	int b = 20;
	char c = 'c';
	//myPrint(a,c); //报错,使用自动类型推导时,不会发生隐式类型转换
	myPrint<int>(a,c);//正确,如果用显示指定类型,可以发生隐式类型转换
}
int main()
{
	test01();
	system("pause");
	return 0;
}

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

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

调用规则如下
1. 如果函数模板和普通函数都可以实现,优先调用普通函数
2. 可以通过空模板参数列表来强制调用函数模板
3. 函数模板也可以发生重载
4. 如果函数模板可以产生更好的匹配,优先调用函数模板
意思就是,例如:当传入的参数为char类型,普通函数形参定义的是int,那么“编译器会觉得隐式转换麻烦“,优先去使用模板函数的实现

示例

void myPrint(int a,int b){
	cout<< "调用的普通函数" <<endl;
}
template<typename T>
void myPrint(T a, T b){
	cout<< "调用的模板" <<endl;
}
template<typename T>
void myPrint(Ta, Tb, Tc){     //重载的函数模板
	cout<< "调用重载的模板" <<endl;
}
void test01(){
	int a = 10;
	int b = 20;
	myPrint(a,b);//优先调用普通函数的实现
	myPrint<>(a, b);//可以通过空模板参数列表来强制调用函数模板
	int c = 30;
	myPrint(a, b, c);//调用重载的函数模板
	char c2 = 'b';
	myPrint(c1, c2);//如果函数模板可以产生更好的匹配,优先调用函数模板charc1='a';
}
int main()
{
	test01();
	system("pause");
	return 0;
}

2.5 模板的局限性

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

template<classT>
void func(T a,T b){
	a=b;
	}

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了

template<classT>
void func(T a,T b){
	if(a>b){...}
};

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
解决
C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板(说白了就是不同的类型,不同的处理,感觉和写普通函数实现差不多了)

三、类模板

3.1 类模板的使用

语法
template< typename T>

template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母

示例

//类模板
template<class T1, class T2>
class Person{
public:
	Person(NameTypename,AgeTypeage){
		this->m_Name = name;
		this->m_Age = age;
	}
	void showPerson(){
		cout<< "name:" << this->m_Name << "age:" << this->m_Age <<endl;
	}
public:
	T1 m_Name;
	T2 m_Age;
};
void test01(){
	//类模板没有自动类型推导的使用方式,要指定NameType为string类型,AgeType为int类型
	Person<string,int>P1("孙悟空",999);
	P1.showPerson();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

注意类模板没有自动类型推导的使用方式,要指定类型

3.2 类模板与函数模板的区别

区别
a. 类模板没有自动类型推导的使用方式,只能用显示指定类型方式
b. 类模板在模板参数列表中可以有默认参数
示例

//有默认参数的类模板
template<class T1,class T2=int>
class Person{
public:
	Person(T1 name,T2 age){
		this->mName = name;
		this->mAge = age;
	}
	void showPerson(){
		cout<< "name:" << this->mName << "age:" << this->mAge <<endl;
	}
public:
	T1 mName;
	T2 mAge;
};
//使用
int main()
{
	Person<string>p("猪八戒",999);//类模板中的模板参数列表可以指定默认参数
	//Person<string,int>p("孙悟空",1000);//必须使用显示指定类型的方式,使用类模板
	p.showPerson();
	system("pause");
	return 0;
}

3.3 类模板中成员函数的的创建时机

类模板中成员函数和普通类中成员函数创建时机的区别:
a. 普通类中的成员函数一开始就可以创建
b. 类模板中的成员函数在调用时才创建

示例

总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建

3.4 类模板对象做函数参数

使用:类模板实例化出的对象,向函数传参的方式
一共有三种传入方式
a. 指定传入的类型 — 直接显示对象的数据类型
b. 参数模板化 — 将对象中的参数变为模板进行传递
c. 整个类模板化 — 将这个对象类型模板化进行传递

示例

总结
1.通过类模板创建的对象,可以有三种方式向函数中进行传参
2.使用比较广泛是第一种:指定传入的类型

3.5 类模板与继承

当类模板碰到继承时,需要注意一下几点
a. 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
b. 如果不指定,编译器无法给子类分配内存
c. 如果想灵活指定出父类中T的类型,子类也需变为类模板

示例

总结:如果父类是类模板,子类需要指定出父类中T的数据类型

3.6 类模板成员函数类外实现

学习目标:能够掌握类模板中的成员函数类外实现
示例

总结:类模板中成员函数类外实现时,需要加上模板参数列表

3.7 类模板分文件编写

问题
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制

示例

总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp

3.8 类模板与友元

类模板配合友元函数的类内和类外实现
a. 全局函数类内实现 - 直接在类内声明友元即可
b. 全局函数类外实现 - 需要提前让编译器知道全局函数的存在
示例

总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别

标签:函数,示例,int,数据类型,C++,类型,泛型,模板
From: https://blog.csdn.net/2401_82458959/article/details/140683628

相关文章

  • (2024最新毕设合集)基于SpringBoot的游乐园管理系统-69394|可做计算机毕业设计JAVA、PHP
    目录1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.1.1经济可行性2.1.2技术可行性2.1.3操作可行性2.2系统流程分析2.2.1系统开发流程2.2.2用户登录流程2.2.3系统操作流程2.2.4添加信息流程2.2.5......
  • C++ 模板(函数模板与类模板)
    原文链接:https://www.cnblogs.com/1873cy/p/18398002模板模板介绍#C++提供了函数模板(functiontemplate)。所谓函数模板。实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡事函数体相同的函数都可以使用这个模板......
  • 如何修改网站模板结构:详细指南
    修改网站模板结构是提升网站设计和用户体验的重要步骤。以下是详细的修改步骤和注意事项,适用于各种类型的网站管理系统:备份网站文件:在进行任何文件修改之前,务必备份网站的所有文件和数据库。您可以使用FTP工具下载网站文件,或者通过网站托管商提供的备份功能进行备份。确保备......
  • 如何修改网站模板:详细教程
    修改网站模板是提升网站设计和用户体验的重要步骤。以下是详细的修改步骤和注意事项,适用于各种类型的网站管理系统:备份网站文件:在进行任何文件修改之前,务必备份网站的所有文件和数据库。您可以使用FTP工具下载网站文件,或者通过网站托管商提供的备份功能进行备份。确保备份文......
  • 百度网站模板修改的步骤与注意事项
    如果您需要修改百度网站的模板,确保网站的外观和功能符合预期,可以遵循以下步骤和注意事项:备份现有模板:在进行任何更改之前,请确保对当前使用的模板进行完整备份。这可以防止意外错误导致网站无法正常运行。获取访问权限:确保您有足够的权限来编辑模板文件。如果您不是管理员,则需要......
  • 如何修改织梦(DedeCMS)网站地图生成模板以优化SEO
    修改织梦(DedeCMS)的网站地图生成模板是优化网站SEO的重要步骤。以下是详细的指南,帮助您顺利完成这一任务:备份现有模板:在进行任何更改之前,请确保对当前使用的网站地图模板进行完整备份。这可以防止意外错误导致网站地图无法正常生成。登录织梦后台管理系统:进入织梦网站的......
  • 你所不知道的 C/C++ 宏知识——基于《C/C++ 宏编程的艺术》
    前言刚学C++的时候,就知道它糅合了四种编程模式:基于预处理器的宏、基于C语言的面向过程、基于类的面向对象、以及基于模板的泛型编程。其中,宏和模板元编程因为是在编译期出结果,能有效提升程序运行期性能,有着独特的价值。宏的缺陷之前了解的宏编程,大多数在数说它的缺陷,以及如......
  • 50个C++经典面试题(01~10)
    为什么要研究面试题,因为研究题目可以让面试者面试时看起来像个专家。本博文将给出50个面试题,题目涉及初级、中级、高级。下面来看下01~10题01:C++是什么?C++的优势是什么?C++是一门面向对象语言,它的存在的目的是为了克服C语言的短板。其中面向对象又涉及如下几个概念:polym......
  • 矩阵乘法与加法模板 Matrix
    更新日志20250119:开工。运算对于矩阵乘法运算\[A\timesB=C\]你可以认为,\(C\)中第\(i\)行第\(j\)列的元素,就是\(A\)的第\(i\)行依次与\(B\)的第\(j\)列相乘的乘积之和。形式化的:\[C_{i,j}=\sum_{k=1}^nA_{i,k}B_{k,j}\]写成代码就是:rep(i,1,n)rep(j,1......
  • C++auto和decltype的用法
    在C++中,auto和decltype是两个非常有用的关键字,它们帮助程序员更方便地处理类型推导和类型声明。以下是它们的具体用法:autoauto关键字用于自动类型推导,即让编译器根据初始化表达式来推断变量的类型。这在处理复杂类型或模板编程时特别有用,因为它可以简化代码并减少类型错误。......