【C++】 ——【模板初阶】——基础详解

目录

1. 泛型编程

1.1 泛型编程的概念

1.2 泛型编程的历史与发展

1.3 泛型编程的优势

1.4 泛型编程的挑战

2. 函数模板

2.1 函数模板概念

2.2 函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5 模板参数的匹配原则

2.6 函数模板的特化

2.7 函数模板的使用注意事项

2.8 函数模板的高级用法

3. 类模板

3.1 类模板的定义格式

3.2 类模板的实例化

3.3 类模板的特化

3.4 类模板成员函数的定义

3.5 类模板的使用注意事项

3.6 类模板的高级用法

结论


 

 

 

823d638fbfbd45f08e401991f36f26ae.pngd6b1d13a84e94373a3d5dffec2d17b20.gif 

专栏:C++学习笔记

第一卷:C++ ———前言知识

第二卷:【C++】——入门基础知识

第二卷升华:【C++】——入门基础知识超详解

第三卷:第一篇【C++】————类与对象(上)-基础知识

第三卷:第一篇升华:剖析【C++】——类与对象(上)超详解——小白篇

第三卷:第二篇:剖析【C++】——类与对象(中)——小白篇—超详解

第三卷:第三篇:剖析【C++】——类和对象(下篇)——超详解——小白篇

第四卷:【C/C++】——小白初步了解——内存管理

在C++中,模板是一种强大的特性,可以实现代码的泛型编程,从而减少代码的重复,提高代码的复用性和可维护性。本文将详细讲解C++模板,涵盖以下几部分内容:

  1. 泛型编程
  2. 函数模板
  3. 类模板

1. 泛型编程

1.1 泛型编程的概念

泛型编程是一种编程范式,旨在编写与类型无关的代码,使得同一段代码能够处理不同的数据类型。这种编程方式提高了代码的通用性和复用性。在C++中,模板是实现泛型编程的核心机制。

1.2 泛型编程的历史与发展

泛型编程的概念最早由Alexander Stepanov和David Musser在1980年代提出。1990年代,泛型编程在C++标准模板库(STL)的实现中得到了广泛应用。STL提供了一组基于模板的容器、算法和迭代器,这些组件极大地提高了C++程序的效率和灵活性。

1.3 泛型编程的优势

  • 代码复用:模板允许开发人员编写一次代码,适用于多种数据类型,减少了代码的重复。
  • 类型安全:模板在编译时进行类型检查,避免了运行时错误。
  • 高效:模板在编译时实例化,生成的代码与手写的特定类型代码一样高效。

1.4 泛型编程的挑战

尽管泛型编程有许多优势,但它也带来了一些挑战:

  • 复杂性:模板代码的语法和错误信息较为复杂,初学者可能难以理解。
  • 编译时间:模板实例化会增加编译时间,尤其是在大型项目中。
  • 代码膨胀:由于模板实例化会生成多个版本的函数或类,可能导致可执行文件的体积增大。

2. 函数模板

2.1 函数模板概念

函数模板是用于创建通用函数的蓝图,允许我们编写与数据类型无关的函数。通过使用函数模板,可以避免为不同数据类型编写相同功能的多个函数,从而减少代码重复。

2.2 函数模板格式

函数模板的定义格式如下:

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

例如,一个简单的加法函数模板:

template <typename T>
T add(T a, T b) {return a + b;
}

2.3 函数模板的原理

函数模板的原理是通过在编译期间进行模板的实例化,将模板参数替换为实际参数类型,从而生成具体的函数版本。例如,调用add<int>(1, 2)会实例化一个int类型的add函数:

int add(int a, int b) {return a + b;
}

2.4 函数模板的实例化

函数模板的实例化可以是显式的或隐式的。隐式实例化是指编译器自动推断模板参数类型,而显式实例化是我们明确指定模板参数类型。例如:

隐式实例化:

add(1, 2); // 推断为 add<int>(1, 2)

显式实例化:

add<int>(1, 2);

2.5 模板参数的匹配原则

模板参数的匹配原则是编译器如何确定模板参数类型的规则。当调用函数模板时,编译器会尝试匹配模板参数和函数参数类型。如果匹配成功,则进行实例化;否则,编译会失败。匹配原则包括:

  1. 类型推断:编译器根据传递的实际参数类型推断模板参数类型。例如,add(1, 2)推断为add<int>(1, 2)
  2. 显式指定:调用模板函数时显式指定模板参数类型。例如,add<int>(1, 2)
  3. 默认参数:模板参数可以有默认类型。例如:
    template <typename T = int>
    T multiply(T a, T b) {return a * b;
    }
    

2.6 函数模板的特化

在某些情况下,我们可能需要对特定类型进行特殊处理,这时可以使用模板特化。模板特化允许我们为某些特定类型定义模板的特化版本。例如:

template <>
const char* add<const char*>(const char* a, const char* b) {static char result[100];strcpy(result, a);strcat(result, b);return result;
}

上述代码特化了add函数模板,使其可以处理const char*类型的字符串连接。

2.7 函数模板的使用注意事项

  1. 模板参数推断:在调用模板函数时,编译器会根据传递的参数推断模板参数类型。如果推断失败,需要显式指定模板参数类型。
  2. 编译错误信息:模板代码的编译错误信息通常比较复杂,调试时需要耐心和细致。特别是在模板嵌套和特化时,错误信息可能难以解读。
  3. 代码膨胀:由于模板实例化会生成多个函数版本,可能导致可执行文件体积增大。每次实例化模板时,都会生成一份新的代码副本,这在某些情况下可能导致二进制文件过大。
  4. 与非模板函数的冲突:在同一作用域中,如果存在与模板函数签名相同的非模板函数,可能会导致二义性和冲突。为避免这种情况,可以使用命名空间或显式实例化来区分模板函数和非模板函数。

2.8 函数模板的高级用法

函数模板的高级用法包括模板参数包(variadic templates)、模板别名(alias templates)等。例如,使用模板参数包实现一个通用的打印函数:

template <typename T>
void print(T arg) {std::cout << arg << std::endl;
}template <typename T, typename... Args>
void print(T arg, Args... args) {std::cout << arg << ", ";print(args...);
}

上述代码利用模板参数包实现了一个递归打印函数,可以处理任意数量的参数。 

3. 类模板

3.1 类模板的定义格式

类模板允许我们创建一个通用的类,该类可以处理不同的数据类型。类模板的定义格式如下:

template <typename T>
class ClassName {// 类成员和方法
};

例如,一个简单的栈(Stack)类模板:

template <typename T>
class Stack {
private:std::vector<T> elements;public:void push(T const& element) {elements.push_back(element);}void pop() {elements.pop_back();}T top() const {return elements.back();}
};

在这个例子中,Stack类模板定义了一个通用的栈,可以存储任意类型的数据。 

3.2 类模板的实例化

类模板的实例化类似于函数模板。例如:

Stack<int> intStack;
intStack.push(1);
intStack.push(2);
intStack.pop();
int topElement = intStack.top();

以上代码实例化了一个int类型的Stack对象,并对其进行了操作。

3.3 类模板的特化

与函数模板类似,我们也可以对类模板进行特化。例如:

template <>
class Stack<bool> {
private:std::vector<bool> elements;public:void push(bool element) {elements.push_back(element);}void pop() {elements.pop_back();}bool top() const {return elements.back();}
};

上述代码特化了Stack类模板,使其可以处理bool类型。

3.4 类模板成员函数的定义

类模板的成员函数可以在类外定义。定义时需要再次指定模板参数。例如:

template <typename T>
void Stack<T>::push(T const& element) {elements.push_back(element);
}template <typename T>
void Stack<T>::pop() {elements.pop_back();
}template <typename T>
T Stack<T>::top() const {return elements.back();
}

这种定义方式使得类模板的实现更加清晰和模块化。

3.5 类模板的使用注意事项

  1. 模板参数推断:在实例化类模板时,需要明确指定模板参数类型,编译器无法自动推断。
  2. 代码膨胀:由于模板实例化会生成多个类版本,可能导致可执行文件体积增大。每次实例化模板时,都会生成一份新的代码副本,这在某些情况下可能导致二进制文件过大。
  3. 编译错误信息:模板代码的编译错误信息通常比较复杂,调试时需要耐心和细致。特别是在模板嵌套和特化时,错误信息可能难以解读。
  4. 与非模板类的冲突:在同一作用域中,如果存在与模板类签名相同的非模板类,可能会导致二义性和冲突。为避免这种情况,可以使用命名空间或显式实例化来区分模板类和非模板类。

3.6 类模板的高级用法

类模板的高级用法包括嵌套模板、模板模板参数(template template parameter)等。例如,使用模板模板参数实现一个通用的容器适配器:

template <typename T, template <typename> class Container = std::deque>
class Stack {
private:Container<T> elements;public:void push(T const& element) {elements.push_back(element);}void pop() {elements.pop_back();}T top() const {return elements.back();}bool isEmpty() const {return elements.empty();}
};

上述代码定义了一个通用的Stack类模板,可以使用不同的容器类型(如std::dequestd::vector等)作为底层存储。 

ae313b7f5e334a7483c315433dae79d7.png

结论

通过函数模板和类模板,C++提供了强大的泛型编程能力,使得代码可以更加通用和复用。在实际编程中,合理地使用模板可以显著提高代码的质量和维护性。希望通过本文的讲解,大家能够对C++模板有一个全面的理解,并能够在自己的项目中灵活应用。

 

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

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

相关文章

事务底层与高可用原理

1.事务底层与高可用原理 事务的基础知识 mysql的事务分为显式事务和隐式事务 默认的事务是隐式事务 显式事务由我们自己控制事务的开启&#xff0c;提交&#xff0c;回滚等操作 show variables like autocommit; 事务基本语法 事务开始 1、begin 2、START TRANSACTION&…

MySQL数据恢复(适用于误删后马上发现)

首先解释一下标题&#xff0c;之所以适用于误删后马上发现是因为太久了之后时间和当时操作的数据表可能会记不清楚&#xff0c;不是因为日志丢失 1.首先确保自己的数据库开启了binlog&#xff08;我的是默认开启的我没有配置过&#xff09; 根据这篇博客查看自己的配置和自己…

AI墓地:738个倒闭AI项目的启示

近年来&#xff0c;人工智能技术迅猛发展&#xff0c;然而&#xff0c;不少AI项目却在市场上悄然消失。根据AI工具聚合网站“DANG”的统计&#xff0c;截至2024年6月&#xff0c;共有738个AI项目停运或停止维护。本文将探讨这些AI项目失败的原因&#xff0c;并分析当前AI初创企…

前端跨域问题--解析与实战

引言 在现代网络应用中&#xff0c;跨域问题是一个常见的挑战。由于浏览器的同源策略&#xff0c;限制了从不同源&#xff08;域名、协议或端口&#xff09;进行资源共享&#xff0c;这就造成了跨域访问的限制。跨域资源共享&#xff08;CORS&#xff09;是一种技术&#xff0…

九、函数的声明和定义

函数声明&#xff1a; 1. 告诉编译器有一个函数叫什么&#xff0c;参数是什么&#xff0c;返回类型是什么。但是具体是不是存在&#xff0c;函数 声明决定不了。 2. 函数的声明一般出现在函数的使用之前。要满足先声明后使用。 3. 函数的声明一般要放在头文件中的。 定义的函…

育才兴业,助力数字产业蓬勃发展

成都树莓集团通过校企合作、建设人才项目转化中心、推动一线多园战略以及提供全方位服务等举措&#xff0c;积极培养数字产业人才&#xff0c;为行业发展提供了有力支持。 一、校企合作&#xff0c;打造人才培养高地 树莓集团深知企业协同育人的重要性&#xff0c;积极与高校建…

某DingTalk企典 - Token

⚠️前言⚠️ 本文仅用于学术交流。 学习探讨逆向知识&#xff0c;欢迎私信共享学习心得。 如有侵权&#xff0c;联系博主删除。 请勿商用&#xff0c;否则后果自负。 网址 aHR0cHM6Ly9kaW5ndGFsay5jb20vcWlkaWFuLw 浅聊一下 没毛病&#xff0c;就这字段&#xff0c;有效期…

java考试题20道

选择题 编译Java源代码文件的命令是javac javac命令是将Java源代码文件进行编译得到字节码文件(.class文件) java命令是在JVM上运行得到的字节码文件 下面是一个示例&#xff1a; javac test.java -------> test.class java test ------> 运行test.class文件下列那…

#LinuxC高级 笔记二

makefile gcc gdb makefile 1. 分文件编程 1.1 源文件&#xff1a;.c结尾的文件 包含main函数的.c 包含子函数的.c 1.2 头文件&#xff1a;.h结尾的文件 头文件、宏定义、typedef 、结构体、共用体、枚举、函数声明 include引用时“”和<>的区别&#xff1a; <>去系…

复合机器人:手脚眼脑的完美结合

在现代工业制造的舞台上&#xff0c;复合机器人如同一位精密而高效的工匠&#xff0c;以其独特的手脚眼脑&#xff0c;正深刻改变着传统的生产方式。这些机器人不仅仅是机械臂的简单延伸&#xff0c;它们汇聚了先进的机械结构、智能的感知系统、精密的控制技术和灵活的思维能力…

【CSAPP】-linklab实验

目录 实验目的与要求 实验原理与内容 实验步骤 实验设备与软件环境 实验过程与结果&#xff08;可贴图&#xff09; 实验总结 实验目的与要求 1.了解链接的基本概念和链接过程所要完成的任务。 2.理解ELF目标代码和目标代码文件的基本概念和基本构成 3.了解ELF可重定位目…

安全和加密常识(6)Base64编码方式

文章目录 什么是 Base64编码原理编解码示例应用什么是 Base64 Base64 是一种用于将二进制数据编码为仅包含64种ASCII字符的文本格式的编码方法,注意,它不是加密算法。它设计的目的主要是使二进制数据能够通过只支持文本的传输层(如电子邮件)进行传输。Base64常用于在需要处…

Python | 基于支持向量机(SVM)的图像分类案例

支持向量机&#xff08;SVM&#xff09;是一种监督机器学习算法&#xff0c;可用于分类和回归任务。在本文中&#xff0c;我们将重点关注使用SVM进行图像分类。 当计算机处理图像时&#xff0c;它将其视为二维像素阵列。数组的大小对应于图像的分辨率&#xff0c;例如&#xf…

三菱PLC标签使用(I/O的映射)与内容

今天&#xff0c;小编继续开始三菱PLC的学习&#xff0c;今天的内容是标签及其标签的内容说明&#xff0c;如果对你有帮助&#xff0c;欢迎评论收藏。 标签的种类&#xff0c;等级&#xff0c;定义 种类 三菱3U的PLC的种类分别为二种&#xff1a;全局标签与局部标签 全局标签…

RabbitMQ-交换机的类型以及流程图练习-01

自己的飞书文档:‌‍‬‍‬‍​‍‬​⁠‍​​​‌⁠​​‬‍​​​‬‬‌​‌‌​​&#xfeff;​​​​&#xfeff;‍​‍​‌&#xfeff;⁠‬&#xfeff;&#xfeff;&#xfeff;​RabbitMQ的流程图和作业 - 飞书云文档 (feishu.cn) 作业 图片一张 画rabbit-mq 消息发…

【HDC.2024】探索无限可能:华为云区块链+X,创新融合新篇章

6月23日&#xff0c;华为开发者大会2024&#xff08;HDC 2024&#xff09;期间&#xff0c; “「区块链X」多元行业场景下的创新应用”分论坛在东莞松山湖举行&#xff0c;区块链技术再次成为焦点。本次论坛以"区块链X"为主题&#xff0c;集结了行业专家、技术领袖、…

深入解读:如何解决微调扩散模型时微调数据集和训练数据集之间的差距过大问题?

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;在微调扩散模型的时候经常会遇到微调数据集和训练数据集之间的差距过大&#xff0c;导致训练效果很差。在图像生成任务中并不明显&#xff0c;但是在视频生成任务中这个问题非常突出。这篇博客深入解读如何…

android应用的持续构建CI(一)-- 总体设计

一、背景 接下里我希望通过一系列的文章&#xff0c;把android应用的构建梳理一遍&#xff0c;从总体设计到逐个环节的实现。 总体设计jenkins集成手动签名依赖环境应用管理 二、构建流程图 三、技术组件 jenkinsjdkgradle360加固 既然是android应用的持续构建&#xff0c…

实验七 SQL数据更新和视图

题目 &#xff08;1&#xff09;向商品类别表category中插入一条记录&#xff08;801&#xff0c;‘座椅套’&#xff0c;‘各种品牌的汽车座套’&#xff09; &#xff08;2&#xff09;向商品表product中插入一条记录&#xff1a;商品编号80101&#xff0c;商品名称“四季通…

64.函数参数和指针变量

目录 一.函数参数 二.函数参数和指针变量 三.视频教程 一.函数参数 函数定义格式&#xff1a; 类型名 函数名(函数参数1,函数参数2...) {代码段 } 如&#xff1a; int sum(int x&#xff0c;int y) {return xy; } 函数参数的类型可以是普通类型&#xff0c;也可以是指针类…