C++编程:模板初阶

news2025/1/21 20:23:07

 

目录

 一、泛型编程

1、通用版交换函数的实现:

2、模板的引入

二、函数模板

1、函数模板的定义和使用

2、函数模板的实例化

三、类模板

1、类模板的定义和实例化


模板是C++的一项强大特性,犹如中国古代四大发明中的活字印刷术与造纸术融为一体一般,给予C++编程强大的复用能力,允许我们编写与类型无关的通用代码,极大地提高了代码的复用性和可维护性。本文将介绍C++模板编程的基础知识,包括函数模板和类模板。 

 一、泛型编程

泛型编程的核心思想就是编写出一串与类型无关的代码。C++中的模板就提供了这样一种方法,让我们可以定义通用的算法和数据结构。

1、通用版交换函数的实现:

 在学习C语言的时候我们经常会自己命名使用到一种交换函数,swap。

//C语言中交换函数的实现与使用

void Swap(int* a, int* b)
{
	int c = *a;
	*a = *b;
	*b = c;
}

int main()
{
	int a = 10, b = 20;
	Swap(&a, &b);
	printf("%d %d", a, b);
	return 0;
}

但是不知道大家是否发现了这一方式的缺陷,没错,就是不能泛用,只能对两个int类型的数据进行交换。倘若我们想要交换两个浮点数类型的数据,又该怎么办呢?

通过前面我们了解了C++不同于C,他支持了函数重载,那我们就多写几个相同内容,相同名字,却只有参数的类型不相同的函数??

传统的函数重载虽然可以实现不同类型的交换:(例如)

void Swap(int* a, int* b)
{
	int c = *a;
	*a = *b;
	*b = c;
}
void Swap(double* a, double* b)
{
	double c = *a;
	*a = *b;
	*b = c;
}
void Swap(char* a, char* b)
{
	char c = *a;
	*a = *b;
	*b = c;
}

可以看见,重载的函数仅仅只是类型不同,代码的复用率极地,只要有新的类型出现,就需要用户自己增加对应的函数。并且代码的可维护性比较低,一个出错可能导致所有的重载出错。

带着这个问题,于是C++中引入了模板,想让编译器根据不同的类型自己生成一个对应的函数。

2、模板的引入

那么什么又是模板呢?

我们想到,打造铁器时通常都是将铁水倒进一个提前准备好的模具里,这样冷却下来的形状就会是模具的形状。

如果在C++中,也能够存在一个这样的模具,通过给这个模具填充不同的材料(数据类型),来获得不同的形状材料(也就是具体类型的代码),那就会节省很多时间与空间,根据这个思想,模板就出现了!


二、函数模板

1、函数模板的定义和使用

函数模板是一种用于定义一组相关函数的蓝图。这些函数模板在使用时会根据实参类型生成具体的函数版本。

以swap为例,我们要写的模板就是:

template <typename T>
void Swap(T& a, T& b)
{
	T c = a;
	a = b;
	b = c;
}

(typename是用来定义模板参数的关键字,也能用class代替)

在编译时,编译器会根据传入的实参类型生成具体类型的函数。例如:

int a = 5, b = 10;
Swap(a, b);  // 编译器生成处理int类型的Swap函数

double x = 5.5, y = 10.5;
Swap(x, y);  // 编译器生成处理double类型的Swap函数

函数模板只是一个蓝图,它本身并不是一个函数,而是编译器用特定方式产生具体类型函数的模具,所以其实模具就是将本来应该由我们做的重复的事情,交给了编译器。

2、函数模板的实例化

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

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

template<typename T>
T Add(const T& left, const T& right) 
{
    return left + right;
}

int main() 
{
    int a = 10, b = 20;
    double x = 10.5, y = 20.5;
    Add(a, b);  // 实例化为int类型的Add函数
    Add(x, y);  // 实例化为double类型的Add函数
    return 0;
}

但如果交换的x与b呢?

这样编译就不会通过,因为在编译期间,当编译器看见该实例化时,需要推演其实参类型,通过实参将T推演为int或者double,但此时模板参数列表只有一个T,编译器无法确定将T转换为int还是double而报错。在模板中,编译器一般不会进行类型转换操作,因为一旦转换出现问题,编译器就得背黑锅,只有普通函数允许自动类型转换。

此时有两种处理方式,第一种时用户强制转换类型,二就是使用显示实例化。

显式实例化:在函数名后的尖括号中指定模板参数的实际类型。

int a = 10;
double b = 20.5;
Add<int>(a, b);  // 显式实例化为int类型的Add函数
//如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

 对于非模板函数和同名函数模板,如果其他条件相同,在调动时会优先调用非模板参数而不会从该模板中产生一个实例。如果模板可以产生一个具有更好匹配的函数,那么才会调用模板进行实例化。

三、类模板

类模板是用于定义一组相关类的蓝图,实例化时根据模板参数生成具体类。

1、类模板的定义和实例化

以一个简单的顺序表为例,

template<typename T>
class Vector 
{
public:
    Vector(size_t capacity = 10)
        : _pData(new T[capacity]), _size(0), _capacity(capacity)
    {

    }

    ~Vector() 
    {
        delete[] _pData;
    }

    void PushBack(const T& data) 
    {
        if (_size < _capacity) 
        {
            _pData[_size++] = data;
        }
    }

    void PopBack() 
    {
        if (_size > 0) 
        {
            --_size;
        }
    }

    size_t Size() const 
    {
        return _size; 
    }

    T& operator[](size_t pos) 
    {
        assert(pos < _size);
        return _pData[pos];
    }

private:
    T* _pData;
    size_t _size;
    size_t _capacity;
};

实例化类模板:

int main() 
{
    Vector<int> vecInt;
    vecInt.PushBack(10);
    vecInt.PushBack(20);

    Vector<double> vecDouble;
    vecDouble.PushBack(10.5);
    vecDouble.PushBack(20.5);

    return 0;
}
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面跟<>,然后将实例化类型放在<>中,类模板的名字不是真正的类,实例化的类才是真正的类。(Vector<int>才是类型)
我们C++中的stl库中的vector,list等容器之所以可以存储不同类型的数据,主要就是运用了类模板。
通过本文的介绍,我们了解了C++模板编程的基本概念和使用方法。模板为我们提供了一种编写高效、可复用代码的手段,极大地提高了代码的通用性和可维护性。通过掌握模板编程的技巧,我们可以编写出更加强大和灵活的C++程序。
希望对大家有所帮助,谢谢观看。

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

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

相关文章

【学习】测试用例设计与执行的黄金法则

在软件测试领域&#xff0c;测试用例的设计与执行是确保产品质量的关键环节。一个优秀的测试用例能够揭示软件中的缺陷&#xff0c;而高效的执行则能保障测试覆盖的全面性。如同璀璨的星辰指引航船前行&#xff0c;以下黄金法则将引领测试用例设计与执行的过程&#xff0c;确保…

uniapp内置的button组件的问题

问题描述 由于想要使用uniapp内置button组件的开放能力&#xff0c;所以就直接使用了button&#xff0c;但是他本身带着边框&#xff0c;而且使用 border&#xff1a;none&#xff1b;是没有效果的。 问题图片 解决方案 button::after {border: none;} 正确样式 此时的分享…

2024 年该如何利用 MidJourney 创作AI艺术(详细教程)

什么是 Midjourney Midjourney 是根据文本提示创建图像的生成式人工智能的优秀范例。与 Dall-E 和 Stable Diffusion 一样&#xff0c;它已成为最受欢迎的人工智能艺术创作工具之一。与竞争对手不同的是&#xff0c;Midjourney 是自筹资金和封闭源代码的&#xff0c;因此对它的…

Java并发核心问题以及并发三特性原子性、可见性、有序性

这篇文章比较长&#xff0c;请耐心看完&#xff0c;相信会让你对并发三大特性有一个较深的理解。 1.原子性(Atomicity) 1.1 原子性定义以及理解 即一个操作或者多个操作&#xff0c;要么全部执行并且执行的过程不会被任何因素打断&#xff0c;要么就都不执行。 一个很经典的…

C/C++学习笔记 C读取文本文件

1、简述 要读取文本文件&#xff0c;需要按照以下步骤操作&#xff1a; 首先&#xff0c;使用该函数打开文本文件fopen()。其次&#xff0c;使用fgets()或fgetc()函数从文件中读取文本。第三&#xff0c;使用函数关闭文件fclose()。 2、每次从文件中读取一个字符 要从文本文…

康谋技术 | 自动驾驶:揭秘高精度时间同步技术(一)

众所周知&#xff0c;在自动驾驶中&#xff0c;主要涵盖感知、规划、控制三个关键的技术层面。在感知层面&#xff0c;单一传感器采集外界信息&#xff0c;各有优劣&#xff0c;比如摄像头采集信息分辨率高&#xff0c;但是受外界条件影响较大&#xff0c;一般缺少深度信息&…

谢宁DOE培训的奇妙之旅:从陌生到熟练

在充满挑战与机遇的现代社会&#xff0c;不断提升自我&#xff0c;掌握新的技能和知识&#xff0c;成为了我们追求进步的重要途径。而对于我来说&#xff0c;参加谢宁DOE培训&#xff0c;无疑是我职业生涯中的一次重要抉择。这次培训让我从对谢宁DOE陌生到熟练&#xff0c;经历…

csrf漏洞与ssrf漏洞

环境&#xff1a;用kali搭建的pikachu靶场 一.CSRF 1.CSRF漏洞简介 跨站请求伪造&#xff08;CSRF&#xff09;漏洞是一种Web应用程序安全漏洞&#xff0c;攻击者通过伪装成受信任用户的请求来执行未经授权的操作。这可能导致用户在不知情的情况下执行某些敏感操作&#xff0…

【python深度学习】——torch.einsum|torch.bmm

【python深度学习】——torch.einsum|torch.bmm 1. 基本用法与示例2. torch.bmm 1. 基本用法与示例 基本用法: torch.einsum(equation, *operands)equation: 一个字符串&#xff0c;定义了张量操作的模式。 使用逗号来分隔输入张量的索引&#xff0c;然后是一个箭头&#xff…

38. 【Java教程】日期和时间处理

本小节我们将学习 Java 中的日期和时间&#xff0c;日期和时间在我们的实际开发中非常常用&#xff0c;例如用户的注册、数据的增删改、对敏感信息的操作等等都需要记录下日期和时间。通过本小节的学习&#xff0c;你将了解到什么是日期、什么是时间、什么是时区&#xff0c;Ja…

ru域名如何申请ssl证书

SSL证书是一种数字证书&#xff0c;通过它可以在客户端和服务器之间建立加密通道&#xff0c;保证数据在传输过程中的安全性。对于.ru域名来说&#xff0c;申请SSL证书可以有效提升网站的安全性&#xff0c;增强用户对网站的信任度&#xff0c;提高网站的排名和权重。今天就随S…

计算机网络 —— 数据链路层(VLAN)

计算机网络 —— 数据链路层&#xff08;VLAN&#xff09; 什么是VLAN为什么要有VLANVLAN如何实现IEEE 802.1Q 我们今天来看VLAN&#xff1a; 什么是VLAN VLAN&#xff08;Virtual Local Area Network&#xff0c;虚拟局域网&#xff09;是一种网络技术&#xff0c;它将一个物…

clickhouse学习笔记(一)入门与安装

目录 一 、入门 简介 核心特性包括 1.1 列式存储 1.2 原生压缩 1.3 向量化执行引擎 1.4 DBMS 功能 1.5 分布式处理 1.6 高吞吐写入能力 1.7 实时分析 1.8 SQL支持 1.9 高度可扩展 1.10 数据分区与线程级并行 1.11 应用场景 1.12 不适用场景 二、ClickHouse单机版…

LabVIEW中PID控制器系统的噪声与扰动抑制策略

在LabVIEW中处理PID控制器系统中的噪声和外部扰动&#xff0c;需要从信号处理、控制算法优化、硬件滤波和系统设计四个角度入手。采用滤波技术、调节PID参数、增加前馈控制和实施硬件滤波器等方法&#xff0c;可以有效减少噪声和扰动对系统性能的影响&#xff0c;提高控制系统的…

View->可拖拽滑动的ImageView + Fling惯性滑动效果 + 回弹效果

XML文件 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:o…

牛客热题:矩阵最长递增路径

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;矩阵最长递增路径题目链接方法一…

铸铁机械5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

铸铁机械5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。工业物联数字孪生平台以5G技术为基础&#xff0c;通过工业物联网连接铸铁机械生产过程中的各个环节&#xff0c;运用数字孪生技术构建虚拟工厂&#xff0c;实现生产过程的实时监测、模拟与优化&#…

人工智能期末复习

&#x1f4cd;人工智能概论期末复习✔️ 知识表示与知识图谱⭐⭐ 知识的特性 相对正确性 不确定性 可表示性与可利用性 知识表示 将人类知识形式化或者模型化。 选择知识表示方法的原则 &#xff08;1&#xff09;充分表示领域知识。 &#xff08;2&#xff09;有利于对…

在线测宽仪的发展历程!

在线测宽仪的发展历程可以归纳为以下几个阶段&#xff1a; 光机扫描式测宽仪阶段&#xff1a; 时间&#xff1a;70年代以前 技术特点&#xff1a;通过机械旋转狭缝机构的扫描&#xff0c;由光电倍增管输出信号&#xff0c;经模拟信号处理得到测量结果。 国内应用&#xff1a;…

全光谱led灯的危害有哪些?曝光低质量全光谱led灯产生的四大风险

眼睛是人类获取信息最重要的感官器官之一&#xff0c;而近视则会导致视力模糊&#xff0c;进而影响学习效果和生活品质。因此&#xff0c;如何保护眼睛&#xff0c;尤其是在学习和使用电子设备时&#xff0c;成为了一个迫切需要解决的问题。然而在护眼领域上&#xff0c;护眼台…