C++ 如何去认识模板

引言:

C++模板是泛型编程的基石,允许程序员定义可与任何数据类型协作的函数和类。这种机制极大地增加了代码的灵活性和复用性,是C++最强大的特性之一。本文将深入探讨C++模板的概念、优势以及使用方法,帮助读者掌握这一重要的编程工具。


文章目录

    • 模板简介
    • 模板的优势
    • 一、模板基础
      • 1.1 模板的概念
      • 1.2 函数模板
      • 1.3 类模板
    • 二、模板进阶
      • 2.1 模板的实例化
      • 2.2 模板的特化
      • 2.3 模板的默认参数
      • 2.4 模板的嵌套
    • 三、模板的应用
    • 结语

模板简介

在软件工程中,“不要重复自己”(DRY)原则鼓励代码的复用。C++模板正是实现此原则的一种强大工具,它使得程序员能够通过编写一套代码,就能够处理多种数据类型。模板可以应用于函数和类,分别称为函数模板和类模板。

模板的优势

使用模板,可以创建通用的算法和数据结构,无需关心具体的数据类型。这样不仅减少了代码的重复,也提高了代码的清晰度和可维护性。例如,下面的代码展示了一个简单的函数模板,用于交换两个变量的值:

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

这个函数模板可以应用于任何支持赋值操作的数据类型,无需为每种类型编写单独的交换函数。

一、模板基础

1.1 模板的概念

模板是一种对类型进行参数化的工具,通过模板可以使用不同的类型来实例化类或函数,从而达到代码复用的目的。C++提供了两种模板:函数模板和类模板。

1.2 函数模板

函数模板是一种特殊的函数,它使用模板类型参数来定义函数,从而使函数能够处理不同类型的数据。函数模板的一般形式如下:

template <typename T>
返回类型 函数名(参数列表) {// 函数体
}

其中,typename可以替换为class,它们在这里是等价的。T是一个类型参数,表示函数可以接受的类型。在函数体内,可以使用T来声明变量、参数,或者作为返回类型。

举一个简单的例子,下面的代码定义了一个函数模板,用于交换两个值:

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

这个函数模板可以用于交换任意类型的两个值,例如:

int i = 1, j = 2; 
swap(i, j);  // 交换两个int string s1 = "hello", s2 = "world"; swap(s1, s2);  // 交换两个string

1.3 类模板

类模板是一种特殊的类,它使用模板类型参数来定义类,从而使类能够处理不同类型的数据。类模板的一般形式如下:

template <typename T> class 类名 {    // 类的定义 
};

在类模板内,可以使用类型参数T来定义成员变量和成员函数。

举一个简单的例子,下面的代码定义了一个类模板Stack,用于表示一个栈:

template <typename T>
class Stack {
private:T* elements;int size;int capacity;
public:Stack(int cap = 10) : elements(new T[cap]), size(0), capacity(cap) {}~Stack() { delete[] elements; }void push(const T& value) { // 实现压栈操作}void pop() {// 实现出栈操作}const T& top() const {// 返回栈顶元素}bool empty() const { return size == 0; }
};

这个类模板可以用于创建任意类型的栈,例如:

Stack<int> intStack;  // 创建一个int型的栈 Stack<string> stringStack;  // 创建一个string型的栈

二、模板进阶

2.1 模板的实例化

当编译器遇到一个模板的使用时,它会根据提供的模板参数,自动生成一个特定类型的函数或类。这个过程称为模板的实例化。

对于函数模板,编译器会在调用点自动推导模板参数的类型。例如:

int a = 1, b = 2; 
swap(a, b);  // 编译器自动推导T为int

对于类模板,必须显式地指定模板参数的类型。例如:

Stack<int> intStack;  // 显式指定T为int

2.2 模板的特化

有时候,我们可能需要为某些特定的类型提供一个特殊的实现。这时,我们可以使用模板的特化。

例如,对于上面的Stack类模板,我们可以为bool类型提供一个特化版本:

template <> class Stack<bool> {    // 为bool类型提供特殊的实现 
};

2.3 模板的默认参数

我们可以为模板参数提供默认值,就像为函数参数提供默认值一样。例如:

template <typename T, int SIZE = 10> class Array {    T elements[SIZE];   // ... 
};

这样,在使用Array类模板时,如果不指定SIZE,则默认为10。

2.4 模板的嵌套

模板可以嵌套使用,即一个模板的定义中可以使用另一个模板。例如:

template <typename T>
class Node {T value;Node<T>* next;// ...
};template <typename T>
class List {Node<T>* head;// ...
};

这里,List类模板中使用了Node类模板。

三、模板的应用

模板在C++标准库中得到了广泛的应用,尤其是在STL(标准模板库)中。STL提供了大量的通用的数据结构和算法,如vectorlistmap等,它们都是通过模板实现的。

例如,vector是一个动态数组,它的定义大致如下:

template <typename T>
class vector {T* elements;int size;int capacity;
public:// ...
};

我们可以使用vector来存储任意类型的对象:

vector<int> intVec;
vector<string> stringVec;

再比如,sort是一个通用的排序算法,它的定义大致如下:

template <typename Iterator> 
void sort(Iterator first, Iterator last) {    // 实现排序算法 }

我们可以使用sort来对任意类型的序列进行排序:

vector<int> intVec = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; 
sort(intVec.begin(), intVec.end());
string str = "helloworld"; 
sort(str.begin(), str.end());

结语

C++模板是一个非常强大的工具,它提供了一种抽象和复用代码的方式,使得我们可以编写出高度泛型的代码。通过对模板的深入理解和灵活运用,我们可以大大提高代码的质量和效率。

当然,模板也不是万能的。过度使用模板可能会导致代码复杂度的增加,编译时间的延长。因此,在使用模板时,我们要权衡其利弊,选择合适的应用场景。

总的来说,C++模板是每一个C++程序员必须掌握的重要工具,希望本文能够帮助您更好地理解和运用模板。

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

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

相关文章

基于vue+element+springboot+uniapp开发的智慧城管源码,java智慧城市管理综合执法系统源码

智慧城管源码&#xff0c;智慧执法&#xff0c;数字化城市管理综合执法系统源码 智慧城管系统充分利用物联网、云计算、信息融合、网络通讯、数据分析与挖掘等技术&#xff0c;对城市管理进行全方位覆盖。它通过建立城市综合管理平台&#xff0c;将城市的信息和管理资源有机结合…

Qt_day5:2024/3/26

作业&#xff1a;实现闹钟 代码&#xff1a; 头文件&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> //定时器事件 #include <QTime> //时间类 #include <QtTextToSpeech> //文本转语音类 #include <…

hgvs中的[数字]是什么意思

hgvs中的[数字],例如NM_144670.6(A2ML1):c.462+9GGA[5]中的[5]详细解释: Repeated Sequences# Repeated sequence: a sequence where, compared to a reference sequence, a segment of one or more nucleotides (the repeat unit) is present several times, one after the…

错误 LNK1104 无法打开文件“mfc140.lib”

如图&#xff0c;编译一个别人已有的项目&#xff0c;我的编译报错为&#xff1a; 但是我所有文件夹全局搜索了一下&#xff0c;这个文件是存在的。但是当前项目访问不到。 更改方法&#xff1a;项目->属性->配置属性->VC目录->库目录 全局搜索找到mfc140.lib的…

【LeetCode 算法专题突破】定长滑动窗口

文章目录 前言[1456. 定长子串中元音的最大数目](https://leetcode.cn/problems/maximum-number-of-vowels-in-a-substring-of-given-length/)题目描述&#xff1a;难度分1263代码与解题思路代码复盘 [2269. 找到一个数字的 K 美丽值](https://leetcode.cn/problems/find-the-k…

如何在pycharm中使用anaconda的虚拟环境

https://blog.csdn.net/weixin_43486940/article/details/123229290

MySQL: 数据类型

数值类型 整型类型 TINYINT&#xff1a;8位SMALLINT&#xff1a;16位MEDIUMINT&#xff1a;24位INT 或 INTEGER&#xff1a;32位BIGINT: 64位 浮点类型 FLOAT&#xff1a;单精度浮点数DOUBLE 或 REAL&#xff1a;双精度浮点数 字符串类型 定长字符串类型 CHAR(size)&…

NAT---网络地址转换技术

Network Address Translation 1、起源&#xff1a;ip地址不够用 2、作用&#xff1a;让私网地址映射成公网地址&#xff0c;进而访问网络。 3、私网Ip地址的范围&#xff1a; A类&#xff1a;10.0.0.0-10.255.255.255 B类&#xff1a;172.16.0.0-172.31.255.255 C类&…

10本程序员必看的书籍

以下是10本程序员必看的书籍推荐&#xff1a; **1.《代码大全》&#xff1a;**史蒂夫迈克康奈尔著。这本书是编程最佳实践指南之一&#xff0c;它详细讲解了如何编写整洁、高效的代码&#xff0c;对于提升编程技能和代码质量有很大帮助。 **2.《深入理解计算机系统》&#xff1…

码垛机与人工搬运:效率与安全性的比较分析

在现代包装行业中&#xff0c;泡沫箱因其轻便和保温特性被广泛用于商品的包装与运输。随着自动化技术的不断发展&#xff0c;码垛机成为提升泡沫箱生产效率、降低劳动强度的关键技术。本文旨在比较码垛机与人工码垛在泡沫箱生产中的优势&#xff0c;并探讨自动化码垛的未来发展…

代码随想录算法训练营DAY3| C++链表Part.1|LeetCode:203.移除链表元素、707.设计链表、206.反转链表

文章目录 203.移除链表元素直接操作原链表虚拟头结点 707.设计链表定义链表结构体MyLinkedList() 初始化 MyLinkedList 对象。int get(int index)void addAtHead(int val)void addAtTail(int val)void addAtIndex(int index, int val)void deleteAtIndex(int index)void printL…

Python程序设计 模块和包

1. 模块和包 1.1 模块&#xff1a; 一个 py 文件&#xff0c;就是一个模块&#xff0c;文件中包括定义的函数和类等信息。 尽管可以 import 多次&#xff0c;实际上模块只导入一次 模块搜索路径内存中已经加载的模块 -> 内置模块 -> sys.path路径&#xff08;导模块的…

Springboot快速整合bootstrap-table使用,接口对接

这个表格加持还是不错了&#xff0c;自带了全局搜索&#xff0c;分页&#xff0c;数据导出&#xff0c;卡片视图&#xff0c;等&#xff0c;本次整合添加了数据添加弹窗和编辑数据回显弹窗&#xff0c;附完整页面代码&#xff0c;只需要拿过来替换自己实际的接口即可。 效果图 …

鸿蒙实战开发-如何通过拖动滑块调节应用内字体大小

介绍 本篇Codelab将介绍如何使用基础组件Slider&#xff0c;通过拖动滑块调节应用内字体大小。要求完成以下功能&#xff1a; 实现两个页面的UX&#xff1a;主页面和字体大小调节页面。拖动滑块改变字体大小系数&#xff0c;列表页和调节页面字体大小同步变化。往右拖动滑块字…

ppp验证实验

实际操作图 1&#xff0c;IP划分分配 [r1]interface Serial 4/0/0 [r1-Serial4/0/0]ip add 192.168.1.1 24 [r2]interface Serial 4/0/0 [r2-Serial4/0/0]ip address 192.168.1.2 24 [r2]int Mp-group 0/0/0 [r2-Mp-group0/0/0]ip add 192.168.2.1 24 [r3]int Mp-group 0/…

Xcode Launching “XXX“ is taking longer than expected

文章目录 1.问题2.如何进入iOS DeviceSupport目录3.解决方法4.参考博客 1.问题 LLDB is likely reading from device memory to resolve symbols 2.如何进入iOS DeviceSupport目录 3.解决方法 进入iOS DeviceSupport目录&#xff0c;删除该真机对应的架构文件&#xff08;比如…

QT作业day3

1、使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…

JMeter 如何并发执行 Python 脚本

要在JMeter中并发执行Python脚本&#xff0c;可以使用Jython脚本或通过调用外部Python脚本的方式实现。 使用Jython脚本并发执行Python脚本的步骤&#xff1a; 1、创建一个线程组&#xff1a;在JMeter界面中&#xff0c;右键点击测试计划&#xff0c;选择 “添加” -> “线…

c语言文件操作(下)

目录 1.文件的随机读写1.1 fseek1.2 ftell1.3 rewind 2. 文件结束的判定2.1 文本文件读取结束的判断2.2 二进制文件读取结束的判断 3. 文件缓冲区 1.文件的随机读写 1.1 fseek 根据⽂件指针的位置和偏移量来定位⽂件指针。 函数原型&#xff1a; int fseek (FILE * stream,…

Springboot+vue的企业质量管理系统(有报告)。Javaee项目,springboot vue前后端分离项目。

演示视频&#xff1a; Springbootvue的企业质量管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…