白骑士的C++教学进阶篇 2.3 模板

系列目录

上一篇:白骑士的C++教学进阶篇 2.2 面向对象编程(OOP)

        模板是C++中一个强大的特性,允许编写通用的代码,提高代码的重用性和灵活性。模板分为函数模板和类模板,还包括模板特化。本篇博客将详细介绍这些内容,帮助您深入理解和应用模板编程。

函数模板

        函数模板允许定义通用的函数,不依赖具体的数据类型。通过参数化类型,函数模板可以用于不同类型的参数。

函数模板的定义与使用

        定义一个函数模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的交换函数:

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

        在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用函数模板交换两个整数和两个字符串,代码如下:

int main() {int x = 10, y = 20;swap(x, y);std::cout << "x: " << x << ", y: " << y << std::endl;std::string str1 = "Hello", str2 = "World";swap(str1, str2);std::cout << "str1: " << str1 << ", str2: " << str2 << std::endl;return 0;
}

        在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的交换功能。

多个模板参数

        函数模板可以有多个模板参数。例如,定义一个比较函数,返回较大的值:

template <typename T1, typename T2>auto max(T1 a, T2 b) -> decltype(a > b ? a : b) {return a > b ? a : b;
}

        使用该模板函数比较不同类型的值,例如:

int main() {int a = 10;double b = 20.5;std::cout << "Max: " << max(a, b) << std::endl;char c = 'A';std::cout << "Max: " << max(a, c) << std::endl;return 0;
}

        在上面的代码中,模板参数 ‘T1‘ 和 ‘T2‘ 分别被推导为 ‘int‘ 和 ‘double‘,实现了通用的比较功能。

类模板

        类模板允许定义通用的类,不依赖具体的数据类型。通过参数化类型,类模板可以用于不同类型的成员变量和方法。

类模板的定义与使用

        定义一个类模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的数组类:

template <typename T>class Array {
private:T* data;int size;public:Array(int s) : size(s) {data = new T[size];}~Array() {delete[] data;}T& operator[](int index) {return data[index];}int getSize() const {return size;}
};

        在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用类模板创建整数数组和字符串数组,例如:

int main() {Array<int> intArray(5);for (int i = 0; i < intArray.getSize(); i++) {intArray[i] = i * 10;}for (int i = 0; i < intArray.getSize(); i++) {std::cout << intArray[i] << std::endl;}Array<std::string> strArray(3);strArray[0] = "Hello";strArray[1] = "World";strArray[2] = "C++";for (int i = 0; i < strArray.getSize(); i++) {std::cout << strArray[i] << std::endl;}return 0;
}

        在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的数组类。

多个模板参数

        类模板可以有多个模板参数。例如,定义一个键值对类:

template <typename K, typename V>class KeyValuePair {
private:K key;V value;public:KeyValuePair(K k, V v) : key(k), value(v) {}K getKey() const {return key;}V getValue() const {return value;}
};

        使用该类模板创建不同类型的键值对,例如:

int main() {KeyValuePair<int, std::string> intStrPair(1, "one");std::cout << "Key: " << intStrPair.getKey() << ", Value: " << intStrPair.getValue() << std::endl;KeyValuePair<std::string, double> strDoublePair("PI", 3.14);std::cout << "Key: " << strDoublePair.getKey() << ", Value: " << strDoublePair.getValue() << std::endl;return 0;
}

        在上面的代码中,模板参数 ‘K‘ 和 ‘V‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的键值对类。

模板特化

        模板特化允许为特定的数据类型提供特殊的实现。当通用的模板代码不能满足特定类型的需求时,使用模板特化可以提供优化或特定功能的实现。

全特化

        全特化是为特定类型提供完全不同的实现。例如,定义一个打印模板函数,并为 ‘char*‘ 类型提供特化:

template <typename T>void print(T value) {std::cout << "Generic print: " << value << std::endl;
}template <>void print<char*>(char* value) {std::cout << "Specialized print: " << value << std::endl;
}

        使用模板函数打印不同类型的值,例如:

int main() {print(42);print(3.14);print("Hello, world!");return 0;
}

        在上面的代码中,‘print‘ 模板函数为 ‘char*‘ 类型提供了特化,实现了不同的打印功能。

偏特化

        偏特化是为模板的某些参数提供特定的实现,而其他参数仍然使用通用模板。例如,定义一个通用的数组类模板,并为指针类型提供偏特化:

template <typename T>class Array {
private:T* data;int size;public:Array(int s) : size(s) {data = new T[size];}~Array() {delete[] data;}T& operator[](int index) {return data[index];}int getSize() const {return size;}
};// 为指针类型提供偏特化
template <typename T>class Array<T*> {
private:T** data;int size;public:Array(int s) : size(s) {data = new T*[size];for (int i = 0; i < size; i++) {data[i] = nullptr;}}~Array() {for (int i = 0; i < size; i++) {delete data[i];}delete[] data;}T*& operator[](int index) {return data[index];}int getSize() const {return size;}
};

        使用该模板类创建指针数组,例如:

int main() {Array<int*> ptrArray(3);for (int i = 0; i < ptrArray.getSize(); i++) {ptrArray[i] = new int(i * 10);}for (int i = 0; i < ptrArray.getSize(); i++) {std::cout << *ptrArray[i] << std::endl;}return 0;
}

        在上面的代码中,模板类 ‘Array‘ 为指针类型提供了偏特化,实现了不同的内存管理。

总结

        模板是C++中一个强大的特性,通过函数模板、类模板和模板特化,程序员可以编写通用、高效的代码,提高代码的重用性和灵活性。理解并熟练掌握模板编程,将大大提高您的编程能力和效率。希望通过本篇博客的介绍,您能更好地理解和应用C++模板,为编写复杂和高效的C++程序打下坚实的基础。

下一篇:白骑士的C++教学进阶篇 2.4 标准模板库(STL)

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

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

相关文章

SQL优化之深分页

SQL优化之深分页 我们都知道&#xff0c;大型项目中的SQL语句&#xff0c;应该尽量避免深分页。 那么问题就来了&#xff1a; 深分页的性能差在哪&#xff1f;什么方案能避免深分页呢&#xff1f; 什么是深分页 深分页&#xff0c;即SQL查询过程中&#xff0c;使用的页数过…

双连通性(算法篇)

算法之双连通性 双连通性 概念&#xff1a; 双连通性就是当删除图中的一个顶点&#xff0c;使图分割成两个图&#xff0c;则这个图就具有双连通性&#xff0c;而能导致图分割成多张图的顶点称为割点背向边&#xff1a;当一个顶点被访问时&#xff0c;选取该顶点其中一个未访…

3.Softmax回归

回归和分类 回归估计一个连续值 分类预测一个离散类别 Softmax回归实际是一个分类问题 从回归到多类分类 对类别进行一位有效编码 y [ y 1 , y 2 , ⋯ , y n ] T y[y_1,y_2,\cdots,y_n]^T y[y1​,y2​,⋯,yn​]T,如果是第i类&#xff0c;则值为1&#xff0c;否则为0 使用…

用户对生活的需求,是三翼鸟创新的起点

这两天又长知识了&#xff0c;学到了一个网络新梗&#xff1a;City不City。 它源自于一种新的打卡方式&#xff0c;用于表达对某个城市的态度或感受。比如你跟朋友在城市游荡时&#xff0c;就可以随口问句City不City啊&#xff1f;通常被释义为“洋不洋气”“ 时髦不时髦”。 …

cpp的cbp

.cbp 文件是 Code::Blocks 的项目文件。Code::Blocks 是一个开源的跨平台集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于 C、C 以及 Fortran 编程。.cbp 文件包含有关项目的所有配置信息&#xff0c;包括文件路径、编译选项、链接器设置等。 以下是 .cbp 文件的…

部署YUM仓库及NFS共享功能

目录 一、YUM仓库服务 1、YUM仓库概述 2、准备安装源 2.1、软件仓库的提供方式 2.2、 RPM软件包的来源 3、YUM主配置文件 4、软件卸载 5、YUM源的提供方式 5.1、配置本地YUM源仓库 5.2、配置ftp源 5.2.1、服务端配置 5.2.2、客户端配置 二、NFS共享存储 1、NFS基…

Git 删除包含敏感数据的历史记录及敏感文件

环境 Windows 10 Git 2.41.0 首先备份你需要删除的文件&#xff08;如果还需要的话&#xff09;&#xff0c;因为命令会将本地也删除将项目中修改的内容撤回或直接提交到仓库中&#xff08;有修改内容无法提交&#xff09; 会提示Cannot rewrite branches: You have unstaged …

免费流程图工具 Draw.io Integration安装使用

Draw.io Integration 是 VS Code 上的一个插件&#xff0c;允许用户在 VS Code 中直接创建、编辑和查看 Draw.io 图表&#xff0c;如流程图、UML 图等。以下是 Draw.io Integration 插件在 VS Code 中的安装步骤&#xff1a; 安装步骤 确保 VS Code 已安装&#xff1a; 如果你…

YOLOv10训练自己的数据集(交通标志检测)

YOLOv10训练自己的数据集&#xff08;交通标志检测&#xff09; 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用YOLOv10训练自己的数据集进行交通标志检测准备数据进行训练进行预测进行验证 参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff…

每日一道算法题 204. 计数质数

题目 204. 计数质数 - 力扣&#xff08;LeetCode&#xff09; Python class Solution:def countPrimes(self, n: int) -> int:"""质数又称为素数&#xff0c;是一个大于1的自然数&#xff0c;除了1和它自身外&#xff0c;不能被其他自然数整除的数叫做质数…

【C++题解】1156 - 排除异形基因

问题&#xff1a;1156 - 排除异形基因 类型&#xff1a;数组基础 题目描述&#xff1a; 神舟号飞船在完成宇宙探险任务回到地球后&#xff0c;宇航员张三感觉身体不太舒服&#xff0c;去了医院检查&#xff0c;医生诊断结果&#xff1a;张三体内基因已被改变&#xff0c;原有…

Vscode连接存在私钥的远程服务器

编辑配置文件 # Read more about SSH config files: https://linux.die.net/man/5/ssh_configHost 172.17.x.xxxHostName 172.17.x.xxxUser xxxIdentityFile C:\Users\xxx\.ssh\xxx.pem会出现报错&#xff1a; Permissions 0644 for xxxx are too open. It is required that …

XML Schema 指示器

XML Schema 指示器 1. 引言 XML Schema 是一种用于定义 XML 文档结构和内容的语言。它提供了一种强大的方式来描述 XML 文档中允许的元素、属性和数据类型。XML Schema 指示器是在 XML Schema 定义中使用的一些特殊元素和属性,它们用于指示 XML 处理器如何解析和验证 XML 文…

vue-router路由路径

在配置 vue-router 路由时&#xff0c;path: ‘search’ 和 path: ‘/search’ 有不同的行为&#xff1a; 1.path: ‘search’: 这是一个相对路径。相对路径意味着这个路径是相对于父路径的。如果父路径是 /emergency&#xff0c;那么这个路由的完整路径是 /emergency/search…

QT 报错C2872: “byte“: 不明确的符号

这个错误提示是因为 byte 这个符号不明确&#xff0c;这种情况是由于代码中同时包含了多个同名符号的定义&#xff0c;编译器无法区分&#xff0c;从而导致错误。在这个问题中&#xff0c;可能是由于使用了 Winsock2.h 头文件中定义的 byte 宏与其他地方定义的 byte 符号重名&a…

Android Bitmap

在Android开发中&#xff0c;位图&#xff08;Bitmap&#xff09;是一个非常重要的图形处理对象&#xff0c;它用于在内存中存储图像数据。以下是关于Android中位图使用的一些关键点和方法&#xff1a; 一、获取位图 从资源文件中获取&#xff1a; 使用BitmapFactory类&#…

头歌资源库(24)插入加号

一、 问题描述 二、算法思想 可以使用动态规划来解决这个问题。 首先将数字串拆分为多个数字&#xff0c;用一个数组nums来存储每个数字。例如&#xff0c;数字串79846会被拆分为数组[7, 9, 8, 4, 6]。 然后定义一个二维数组dp&#xff0c;其中dp[i][j]表示在前i个数字中插入…

Java异常体系、UncaughtExceptionHandler、Spring MVC统一异常处理、Spring Boot统一异常处理

概述 所有异常都是继承自java.lang.Throwable类&#xff0c;Throwable有两个直接子类&#xff0c;Error和Exception。 Error用来表示程序底层或硬件有关的错误&#xff0c;这种错误和程序本身无关&#xff0c;如常见的NoClassDefFoundError。这种异常和程序本身无关&#xff0…

Java网络模型全扫盲

概述 讲述ava层面NIO基础知识&#xff0c;用作基础回顾所用 1. NIO概述 ​ 在Java中&#xff0c;NIO&#xff08;Non-blocking I/O 或 New I/O&#xff09;是Java SE 1.4及后续版本中引入的一套新的输入/输出操作API。 ​ 它与传统的IO模型相比&#xff0c;提供了更高的效率和…

【算法】二叉树-迭代法实现前后中序遍历

递归的实现就是:每一次递归调用都会把函数的局部变量&#xff0c;参数值和返回地址等压入调用栈中&#xff0c;然后递归返回的时候&#xff0c;从栈顶弹出上一次递归的各项参数&#xff0c;这就是递归为什么可以返回上一层位置的原因 可以用栈实现二叉树的前中后序遍历 1. 前序…