【C++初阶】第六站 : 模板初阶

这篇具有很好参考价值的文章主要介绍了【C++初阶】第六站 : 模板初阶。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:
本章知识点:泛型编程、函数模板、类模板
专栏: C++初阶

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

目录

泛型编程

函数模板

1.函数模板概念

2.函数模板格式

3.函数模板的原理

4.函数模板的实例化

5.模板参数的匹配原则

类模板

类模板的定义格式

类模板的实例化


泛型编程

如何实现一个通用的交换函数呢?
代码如下:
#include<iostream>
using namespace std;
//函数重载
void Swap(int& left, int& right)
{
	int tmp = left;
	left = right;
	right = tmp;
}
void Swap(double& left, double& right)
{
	double tmp = left;
	left = right;
	right = tmp;
}
void Swap(char& left, char& right)
{
	char tmp = left;
	left = right;
	right = tmp;
}
int main()
{
	int x = 10, y = 20;
	Swap(x, y);
	cout << x << " " << y << endl;

	double a= 100.1, b = 200.1;
	Swap(a, b);
	cout << a << " " << b << endl;

	char c = ' c', d = 'd';
	Swap(c, d);
	cout << c << " " << d << endl;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

🚩使用函数重载虽然可以实现,但是有一下几个不好的地方:

  • 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  • 代码的可维护性比较低,一个出错可能所有的重载均出错
那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 呢?
【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶
如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

函数模板

1.函数模板概念

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

2.函数模板格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
template<class T>
void Swap(T& left, T& right)
{
	T tmp = left;
	left = right;
	right = tmp;
}
int main()
{
	int i = 100, j = 1;
	Swap(i, j);
	cout << i << " " << j << endl;

	double x = 22.22, y = 11.11;
	Swap(x, y);
	cout << x << " " << y << endl;
	return 0;
}
【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶
注意 :typename是用来定义模板参数关键字也可以使用class( 切记:不能使用struct代替class )

3.函数模板的原理

      那么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。有人给出了论调:懒人创造世界。
【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶
📚函数模板 是一个 蓝图 它本身并不是函数, 是编译器用使用方式 产生特定具体类型函数的模具
所以其实模板就是将本来应该我们做的重复的事情交给了编译器
【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶
     在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

4.函数模板的实例化

用不同类型的参数使用函数模板时称为函数模板的实例化
模板参数实例化分为: 隐式实例化和显式实例化
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	return 0;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

引入一个知识:这里的两个Swap调的是不是同一个函数?
 
#include<iostream>
using namespace std;
template<class T>
void Swap(T& left, T& right)
{
	T tmp = left;
	left = right;
	right = tmp;
}
int main()
{
		int i = 100, j = 1;
		Swap(i, j);           //   <----函数1
		cout << i << " " << j << endl;

		double x = 100.1, y = 1.1;
		Swap(x, y);          //    <----函数2
		cout << x << " " << y << endl;
		return 0;
}

通过查看反汇编,发现编译器调用的是不同的函数,因为:要调这个函数就要建立栈帧,由于传入的函数参数的数据类型不一样,那么建立的栈帧大小也是不一样的,int为4byte而double为8byte.

所以导致生成的指令也不一样 --> 证明不是调用同一个函数

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

以下这个代码能够通过编译吗?

#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1= 10, a2 = 20;
	double b1 = 100.1, b2 = 200.2;
	cout << Add(a1, b2)<<endl;
}

结果是不能的:

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

  • 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
  • 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错
  • 注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅 Add(a1, d1);

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
1.想解决类型匹配可以使用强制类型转换:
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1= 10, a2 = 20;
	double d1 = 100.1, d2 = 200.2;
	cout << Add(a1, (int)d1)<<endl;
	cout << Add((double)a1, d1) << endl;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

注意:隐式类型转换和强制类型转换不会改变原有的类型,只是生成了一个临时变量。

2.使用显式实例化
显式实例化:在函数名后的 <> 中指定模板参数的实际类型
#include<iostream>
using namespace std;
int main()
{
	int a = 10;
	double b = 20.20;

	// 显式实例化
	cout << Add<int>(a, b)<<endl;
	cout << Add <double>(a, b) << endl;
	return 0;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	cout << Add<int>(1, "1") << endl;
	return 0;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

5.模板参数的匹配原则

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

代码如下:

#include<iostream>
using namespace std;
// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
int main()
{
	   // 与非模板函数匹配,编译器不需要特化
	cout << Add(1, 2) << endl;
	   // 调用编译器特化的Add版本
	cout << Add<char>('1', '2') << endl;
}

【C++初阶】第六站 : 模板初阶,C++,c++,vs2019,编程语言,笔记,模板初阶

  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
#include<iostream>
using namespace std;
// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
int main()
{
	// 与非函数模板类型完全匹配,不需要函数模板实例化
	cout << Add(1, 2) << endl;
	// 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
	cout << Add(1, 2.2) << endl;
}
  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

类模板

类模板的定义格式

template < class T1 , class T2 , ..., class Tn >
class 类模板名
{
// 类内成员定义
};
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{ 
public :
 Vector(size_t capacity = 10)
 : _pData(new T[capacity])
 , _size(0)
 , _capacity(capacity)
 {}
 
 // 使用析构函数演示:在类中声明,在类外定义。
     ~Vector();
 
     void PushBack(const T& data);
     void PopBack();
 // ...
 
     size_t Size() {return _size;}
 
     T& operator[](size_t pos)
     {
         assert(pos < _size);
         return _pData[pos];
     }
 
private:
     T* _pData;
     size_t _size;
     size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
     if(_pData)
     delete[] _pData;
     _size = _capacity = 0;
}

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
// Vector类名,Vector<int>才是类型
Vector < int > s1 ;
Vector < double > s2 ;

🔧本文修改次数:0

🧭更新时间:2024年3月10日文章来源地址https://www.toymoban.com/news/detail-840713.html

到了这里,关于【C++初阶】第六站 : 模板初阶的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++——模板初阶与泛型编程

    🌸作者简介: 花想云 ,在读本科生一枚,致力于 C/C++、Linux 学习。 🌸 本文收录于 C++系列 ,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,专为大学生打造全套 C++ 学习教程,持续更新! 🌸 相关专栏推荐: C语言初阶系列 、 C语言进阶系列 、 数据结构与算法 本章我们

    2023年04月17日
    浏览(36)
  • 第三章:R语言编程 第六节:模块模式

    模块是一种结构,由无法从外部访问的数据以及操纵这些数据的函数组成,是标准化代码编写技术 模块模式的优点 1.因为无法从外部访问数据,所以很好的隐藏了内部实现,说人话就是无需考虑数据在模块内部是如何保存的 2.其次,因为只能借助实现定义的函数访问模块内部

    2024年03月11日
    浏览(38)
  • 算法初阶双指针+C语言期末考试之编程题加强训练

    常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。 对撞指针:⼀般⽤于顺序结构中,也称左右指针。 • 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼 近。 • 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(

    2024年02月05日
    浏览(49)
  • C语言初阶测评题:测试你的基础知识和编程技能!!

    💓博客主页:江池俊的博客 ⏩收录专栏:C语言刷题专栏 👉专栏推荐:✅C语言初阶之路 ✅C语言进阶之路 💻代码仓库:江池俊的代码仓库 🎉欢迎大家点赞👍评论📝收藏⭐ 🎈前言: 欢迎来到这个关于C语言的初阶测评题博客!在这里,我们将为您呈现一系列考察基础知识

    2024年02月11日
    浏览(34)
  • Golang vs Java: 一场编程语言的较量

    在IT行业飞速发展的过程中,编程语言扮演着至关重要的角色。作为开发人员,选择合适的编程语言对于构建高效、可靠和可维护的应用程序至关重要。在这场编程语言的较量中,Golang和Java无疑是两个备受青睐的选择。我们现在将对这两种语言进行全面对比,探讨它们在性能、简洁

    2024年04月17日
    浏览(51)
  • Golang vs Rust ——服务端编程应该选择哪种语言

    为服务端编程选择一种语言应该基于你的长期目标和项目的要求,因此,盲目地问我应该雇用 Go 开发人员还是应该选择 Rust 进行开发并不能帮助你解决问题。 然而,如果你发现自己陷入了困境,那么这篇文章将为你解惑。下面让我们开始吧。 Go 是一种静态类型的、AOT 编译的

    2024年02月02日
    浏览(57)
  • Lua中文语言编程源码-第六节,更改lmathlib.c 数学库函数, 使Lua加载中文库关键词(与数学库相关)

    源码已经更新在CSDN的码库里: 在src文件夹下的lmathlib.c 数学库 函数,Standard mathematical library:表明这个C源文件实现了Lua的标准数学库(Standard mathematical library),即提供了与数学相关的API和功能实现。 增加中文版mathlib数学函数名列表,保留英文版mathlib数学函数名列表。 原

    2024年03月27日
    浏览(78)
  • 玄子Share-自然语言编程(NLP)_快速了解知识向 ChatGPT 提问的最佳模板

    以下内容均为 ChatGPT 回答 玄子: 我向你提问时,问题描述精确的重要性 ChatGPT 3.5 问题描述的精确性非常重要,因为它可以让回答者更好地理解您的问题,并且更容易提供准确和有用的解决方案。如果问题描述不够清晰或不够详细,回答者可能会误解您的问题或者理解不到位

    2024年02月08日
    浏览(52)
  • 【编程】C++语言编程规范-2

    结合C++ Effective系列参考树、尤其是工程经验教训的总结。 并发 除非必要,尽量少用线程。 多线程编程要守护好内存,使用atomic、mutex、condition variable、future、semaphore、latch、barrier等同步机制避免数据竞争。 尽量缩小临界区,临界区指独占的资源,禁止其他线程访问变量的代

    2024年02月21日
    浏览(50)
  • 玄子Share-自然语言编程(NLP)_Java开发小白向 ChatGPT 提问的最佳模板

    以下内容均为 ChatGPT 回答 玄子: 我向你提问时,问题描述精确的重要性 ChatGPT 3.5 问题描述的精确性非常重要,因为它可以让回答者更好地理解您的问题,并且更容易提供准确和有用的解决方案。如果问题描述不够清晰或不够详细,回答者可能会误解您的问题或者理解不到位

    2023年04月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包