【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 类模板的高级用法

结论


 

 

 

专栏: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等)作为底层存储。 

结论

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux CentOS 宝塔中禁用php8.2的eval函数详细图文教程

PHP_diseval_extension 这个方法是支持PHP8的, Suhosin禁用eval函数&#xff0c;不支持PHP8 一、安装 cd / git clone https://github.com/mk-j/PHP_diseval_extension.gitcd /PHP_diseval_extension/source/www/server/php/82/bin/phpize ./configure --with-php-config/ww…

美团校招机试 - 小美的平衡矩阵(20240309-T1)

题目来源 美团校招笔试真题_小美的平衡矩阵 题目描述 小美拿到了一个 n * n 的矩阵&#xff0c;其中每个元素是 0 或者 1。 小美认为一个矩形区域是完美的&#xff0c;当且仅当该区域内 0 的数量恰好等于 1 的数量。 现在&#xff0c;小美希望你回答有多少个 i * i 的完美…

C++操作系列(二):VSCode安装和配置C++开发环境

1. VSCode下载 进入VSCode的官网网页&#xff1a;Download Visual Studio Code - Mac, Linux, Windows 下载相应的版本&#xff1a; 2. 安装VSCode 安装到指定位置&#xff1a; 一路下一步&#xff0c;直至安装完成&#xff1a; 3. 安装C插件 3.1. 安装C/C 点击扩展图标&…

linux上git的使用

目录 1.测试是否安装有git 2.下载项目到本地 3.三板斧 1.将代码放在创建的目录中 2.提交改动到本地 3.提交代码到远端 4.注意点 以及补充内容 1.测试是否安装有git 如果输入git --help 会显示下面一大串那么就是已经安装&#xff0c;否则需要自行手动安装 yum install g…

Elasticsearch开启认证|为ES设置账号密码|ES账号密码设置|ES单机开启认证|ES集群开启认证

文章目录 前言单节点模式开启认证生成节点证书修改ES配置文件为内置账号添加密码Kibana修改配置验证 ES集群开启认证验证 前言 ES安装完成并运行&#xff0c;默认情况下是允许任何用户访问的&#xff0c;这样并不安全&#xff0c;可以为ES开启认证&#xff0c;设置账号密码。 …

【Python从入门到进阶】59、Pandas库中Series对象的操作(二)

接上篇《58、Pandas库中Series对象的操作(一)》 上一篇我们讲解了Pandas库中Series对象的基本概念、对象创建和操作&#xff0c;本篇我们来继续学习Series对象的运算、函数应用、时间序列操作&#xff0c;以及Series的案例实践。 一、Series对象的运算 1. 数值型数据的算术运…

ElasticSearch索引架构与存储

关于ES官网的介绍: Elasticsearch provides near real-time search and analytics for all types of data. Whether you have structured or unstructured text, numerical data, or geospatial data, Elasticsearch can efficiently store and index it in a way that support…

详细介绍MySQL的索引(下)

索引的使用 同一条数据在未创建索引的情况下耗时&#xff1a; nick字段是未创建索引的 select * from t_user WHERE nick 邹丽;SHOW PROFILES; 耗时为&#xff1a; user_account字段创建了唯一索引 select * from t_user WHERE user_account 13781945844;SHOW PROFILES;…

基于Vue3 + Typescript 封装 Element-Plus 组件

1. 课程简介 项目地址 git clone https://gitee.com/childe-jia/my-message.git 背景: 该课程是基于Vue3 Typescript Vite构建, 教会大家封装Element-Plus组件 具备能力: 最新的 Vue3 及相关技术组件的设计思想大厂的开发模式/代码规范 技术: Vue3 首次渲染 / diff 算法 …

5-linux文件路径与文件目录系统

目录 ①文件路径 目录跳转 绝对路径与相对路径 ②文件目录系统 目录系统组成 目录命名规则 命令补充 ls命令补充 file filename查看文件类型 less查看文本文件 ①文件路径 目录跳转 pwd:查看当前工作目录。 cd:改变目录。 ls:列出目录内容。 [root########## ~]# …

取证工作:怎样解锁 LUKS2 加密磁盘?

对于 LUKS2 密码进行恢复&#xff0c;Elcomsoft Distributed Password Recovery &#xff08;简称 EDPR&#xff09; 软件可以构建高性能集群&#xff0c;以更快地破解密码。EDPR 软件提供零开销的可扩展性&#xff0c;并支持 GPU 加速&#xff0c;以加快恢复速度。EDPR 可帮助…

下属无执行力,领导无能为力?用好这3大法则,打造一流行动力

下属无执行力&#xff0c;领导无能为力&#xff1f;用好这3大法则&#xff0c;打造一流行动力 第一个&#xff1a;漏斗法则 在沟通这个领域&#xff0c;有一个漏斗法则&#xff0c;意思就是指&#xff1a;如果你脑袋里面想表达的是100%&#xff0c;那你说出口的会只有80%&…

开发板以电脑为跳板连接互联网

标题 开发板以电脑为跳板连接互联网网络共享方式桥接方式 开发板以电脑为跳板连接互联网 分享下用网线直连电脑的开发板如何以电脑为跳板连接互联网的两个方法。 网络共享方式桥接方式 补充下&#xff0c;我的电脑连接的是无线网络&#xff0c;开发板和电脑是用网线进行连接的…

AI奏响未来乐章:音乐界的革命性变革

AI在创造还是毁掉音乐 引言 随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;正在逐渐渗透到我们生活的每一个角落&#xff0c;音乐领域也不例外。AI技术的引入&#xff0c;不仅为音乐创作、教育、体验带来了革命性的变革&#xff0c;更为整个音乐产业注入了…

昇思25天学习打卡营第7天|模型训练

模型训练 模型训练一般分为四个步骤&#xff1a; 构建数据集。定义神经网络模型。定义超参、损失函数及优化器。输入数据集进行训练与评估。 前面几天依次学习了前面几个步骤的操作&#xff0c;今天继续学习模型训练。 数据集和神经网络模型这个前面已经有详细的介绍。准确…

生成式AI如何赋能教育?商汤发布《2024生成式AI赋能教育未来》白皮书

生成式AI正在各个行业中展现出巨大的应用前景。在关系国计民生的教育行业&#xff0c;生成式AI能够催生哪些创新模式&#xff1f; 6月28日&#xff0c;商汤科技受邀参加2024中国AIGC应用与发展峰会&#xff0c;并在会上发布《2024生成式AI赋能教育未来》白皮书&#xff0c;提出…

Qt:5.QWidget属性介绍(isEnabled和geometry)

目录 一、 QWidget属性的介绍&#xff1a; 二、Enabled属性&#xff1a; 2.1Enabled属性的介绍&#xff1a; 2.2获取控件当前可用状态的api——isEnabled()&#xff1a; 2.3设置控件当前的可用状态的api—— setEnabled() &#xff1a; 2.4 实例&#xff1a;通过一个按钮&…

【人工智能学习之图像操作(六)】

【人工智能学习之图像操作&#xff08;六&#xff09;】 Hough变换直线检测圆检测 图像分割 Hough变换 在图像处理中&#xff0c;霍夫变换用来检测任意能够用数学公式表达的形状&#xff0c;即使这个形状被破坏或者有点扭曲 直线检测 import cv2 import numpy as np image …

Python 基础:用 json 模块存储和读取数据

目录 一、用 json 存储数据二、用 json 读取数据 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&#xff1a;从入门到实践&#xff08;第2版&#xff09;》 用户关闭程序时&#…

Redux实现Token持久化

业务背景: Token数据具有一定的时效时间&#xff0c;通常在几个小时&#xff0c;有效时间内无需重新获取&#xff0c;而基于Redux的存储方式又是基于内存的&#xff0c;刷新就会丢失&#xff0c;为了保持持久化&#xff0c;我们需要单独做处理 解决方案&#xff1a; 使用redu…