C++ 模板编程:解锁高效编程的神秘密码

news2024/10/28 1:07:32

 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。

 


目录

💯前言

💯泛型编程

💯函数模板

1.函数模板概念

2.函数模板格式

3.函数模板的原理

4.函数模板的实例化

5.模板参数的匹配原则

💯类模板

1.类模板的定义格式

2.类模板的实例化

💯总结


💯前言

😖在编程的世界中,你是否曾经为了处理不同类型的数据而不得不重复编写大量相似的代码?

😖你是否渴望有一种方法能够让代码更加通用、灵活,提高代码的复用性呢?

👀如果你的答案是肯定的,那么 C++ 的模板编程或许就是你一直在寻找的解决方案。

模板编程包含了🚩泛型编程、🚩函数模板和🚩类模板三个重要部分,犹如三把利器,助力我们在编程的征程上披荆斩棘。 

 


💯泛型编程

🌠“在编程过程中,当需要实现一个通用的交换函数时,如果不采用特殊的手段,会面临哪些问题呢❓”

void Swap(int& left, int& right)
{
    int temp = left;
    left = right;
    right = temp;
}

void Swap(double& left, double& right)
{
    double temp = left;
    left = right;
    right = temp;
}

void Swap(char& left, char& right)
{
    char temp = left;
    left = right;
    right = temp;
}

这样做有很多不好的地方,比如代码复用率低,只要有新类型出现,就得增加对应的函数;而且代码的可维护性也低,一个地方出错可能所有重载都出错。

泛型编程可以很好地解决这个问题。 

泛型编程是一种编写与类型无关的通用代码的手段,就如同拥有一个神奇的 “模具”,我们可以向这个模具中填充不同的 “材料”(类型),从而得到不同类型的 “铸件”(生成具体类型的代码)。 

👇模板是泛型编程的基础。


💯函数模板

🌠“如何实现一个可以适应不同类型参数的通用函数呢?”

 

1.函数模板概念

函数模板代表了一个函数家族,它与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

比如下面这个函数模板: 

template<typename T>
void Swap( T& left, T& right)
{
    // 临时变量存储 left 的值
    T temp = left;
    left = right;
    right = temp;
}

😀这个模板可以根据不同的类型生成对应的交换函数。

2.函数模板格式

template<typename T1, typename T2,......,typename Tn> 
返回值类型 函数名 (参数列表){}

这里的 “typename” 是用来定义模板参数的关键字,也可以用 “class”,但不能用 “struct” 代替 “class”。

3.函数模板的原理

函数模板就像是一个蓝图,它本身不是一个具体的函数,而是编译器用来生成具体类型函数的模具。在编译器编译阶段,当我们使用函数模板时,编译器会根据传入的实参类型来推演生成对应类型的函数。

🍏例如,当我们用 double 类型的参数调用这个函数模板时,编译器会将模板参数 “T” 确定为 double 类型,然后生成一份专门处理 double 类型的代码

4.函数模板的实例化

  • 隐式实例化:让编译器根据实参推演模板参数的实际类型。
  • 显式实例化:在函数名后的 “<>” 中指定模板参数的实际类型。

👇比如下面这个函数模板的使用:

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

int main()
{
    int a1 = 10, a2 = 20;
    double d1 = 10.0, d2 = 20.0;
    Add(a1, a2); // 隐式实例化,编译器推演出 T 为 int 类型
    🌠Add(d1, d2); // 隐式实例化,编译器推演出 T 为 double 类型
    🌠Add<int>(a1, b1); // 显式实例化,指定 T 为 int 类型
}

5.模板参数的匹配原则

  • 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。👀👀​​​​​​​👀
    #include <iostream>
    
    // 非模板函数
    void printValue(int value) {
        std::cout << "非模板函数:值为 " << value << std::endl;
    }
    
    // 函数模板
    template <typename T>
    void printValue(T value) {
        std::cout << "函数模板:值为 " << value << std::endl;
    }
    
    int main() {
        int num = 10;
        printValue(num); // 调用非模板函数,因为有精确匹配
    
        double dnum = 3.14;
        printValue(dnum); // 调用函数模板实例化后的版本,参数类型为 double
    
        return 0;
    }
  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。👀👀​​​​​​​👀
    #include <iostream>
    
    // 非模板函数
    void printValue(int value) {
        std::cout << "非模板函数:值为 " << value << std::endl;
    }
    
    // 函数模板
    template <typename T>
    void printValue(T value) {
        std::cout << "函数模板:值为 " << value << std::endl;
    }
    
    int main() {
        int num = 10;
        printValue(num); // 优先调用非模板函数,因为参数精确匹配非模板函数
    
        double dnum = 3.14;
        printValue(dnum); // 没有精确匹配的非模板函数,调用函数模板实例化后的版本,参数类型为 double
    
        // 现在传入一个 long long 类型,没有对应的非模板函数,模板能产生更好匹配
        long long lnum = 1234567890123;
        printValue(lnum); // 调用函数模板实例化后的版本,参数类型为 long long
    
        return 0;
    }

  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。👀👀​​​​​​​👀
    #include <iostream>
    
    // 普通函数,可以进行自动类型转换
    void printValue(int value) {
        std::cout << "普通函数:值为 " << value << std::endl;
    }
    
    // 函数模板
    template <typename T>
    void printValue(T value) {
        std::cout << "函数模板:值为 " << value << std::endl;
    }
    
    int main() {
        // 普通函数可以自动将 double 类型转换为 int 类型进行调用
        double d = 3.14;
        printValue(static_cast<int>(d)); 
    
        // 函数模板不能自动将 double 类型转换为 int 类型进行调用
        // printValue(d);  // 这会导致编译错误
    
        return 0;
    }

💯类模板

🌠“如果想要定义一个可以适应不同类型数据的通用类,应该怎么做呢?”

1.类模板的定义格式

template<class T1, class T2,..., class Tn> 
class 类模板名 
{
    // 类内成员定义
}

 例如,定义一个动态顺序表类模板:

template<class T>
class Vector
{
public :
    Vector(size_t capacity = 10)
        : _pData(new T[capacity])
    , _size(0)
    , _capacity(capacity)
    {}
    // 析构函数,释放动态分配的内存
    ~Vector();
    void PushBack(const T& data);
    void PopBack();
    size_t Size() {return _size;}
    T& operator[](size_t pos)
    {
        assert(pos < _size);
        return _pData[pos];
    }
private:
    T* _pData;
    size_t _size;
    size_t _capacity;
};

2.类模板的实例化

类模板实例化与函数模板实例化不同,需要在类模板名字后跟 “<>”,然后将实例化的类型放在 “<>” 中,这样才能得到真正的类。

template <class T>
Vector<T>::~Vector()
{
    if(_pData)
        delete[] _pData;
    _size = _capacity = 0;
}

int main()
{
    // Vector 不是具体的类,Vector<int>才是真正的类
    Vector<int> s1;
    Vector<double> s2;
}

💯总结

 

🔥C++ 的模板编程为我们提供了强大的工具,让我们能够编写更加通用、灵活和高效的代码。

📍​​​​​​​无论是泛型编程、函数模板还是类模板,都能在不同的场景下发挥巨大的作用。📍


以后我将深入研究继承、多态、模板等特性,并将默认成员函数与这些特性结合,以解决更复杂编程问题!欢迎关注我👉【A Charmer】 

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

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

相关文章

如何使用DBeaver连接flink

通过DBeaver配置并连接flink&#xff1a; 1. 打开Dbeaver&#xff0c;选择“数据库”--》“数据库驱动管理器” 2.在驱动管理器界面点击新建按钮 3.在新建弹窗输入flink相关的驱动信息&#xff0c;主要包括&#xff1a; org.apache.flink.table.jdbc.FlinkDriver jdbc:flink…

Spring+ActiveMQ

1. 环境搭建 1.1 env-version JDK 1.8 Spring 2.7.13 Maven 3.6 ActiveMQ 5.15.2 1.2 docker-compose.yml version: 3.8services:activemq:image: rmohr/activemq:5.16.3container_name: activemqports:- "61616:61616"- "8161:8161"environment…

图解:什么是多租户?

大家好&#xff0c;我是汤师爷~ 什么是多租户&#xff1f; 多租户是SaaS&#xff08;软件即服务&#xff09;领域里特有的一个概念。在SaaS服务中&#xff0c;“租户”指的就是使用这个SaaS系统的客户。 那么租户和用户有什么区别呢&#xff1f;举个例子。假设你正在使用一款…

SQL实战训练之,力扣:1532最近的三笔订单

目录 一、力扣原题链接 二、题目描述 三、建表语句 四、题目分析 五、SQL解答 六、最终答案 七、验证 八、知识点 一、力扣原题链接 1532. 最近的三笔订单 二、题目描述 客户表&#xff1a;Customers ------------------------ | Column Name | Type | --------…

【C++单调栈 贡献法】907. 子数组的最小值之和|1975

本文涉及的基础知识点 C单调栈 LeetCode907. 子数组的最小值之和 给定一个整数数组 arr&#xff0c;找到 min(b) 的总和&#xff0c;其中 b 的范围为 arr 的每个&#xff08;连续&#xff09;子数组。 由于答案可能很大&#xff0c;因此 返回答案模 109 7 。 示例 1&#x…

ArcGIS计算多个面要素范围内栅格数据各数值的面积

本文介绍在ArcMap软件中&#xff0c;基于面积制表工具&#xff08;也就是Tabulate Area工具&#xff09;&#xff0c;基于1个面要素数据集与1个栅格数据&#xff0c;计算每一个面要素中各栅格数据分布面积的方法。 首先&#xff0c;来看一下本文的需求。现有一个矢量面的要素集…

动态规划 —— 斐波那契数列模型-解码方法

1. 解码方法 题目链接&#xff1a; 91. 解码方法 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/decode-ways/description/ 2. 题目解析 1. 对字母A - Z进行编码1-26 2. 11106可以解码为1-1-10-6或者11-10-6, 但是11-1-06不能解码 3. 0n不能解码 4. …

springboot项目测试环境构建出的依赖包比本地构建出的依赖包多

本地能够正常启动服务&#xff0c;但是测试环境启动报错。 上述druid是服务pom文件中之前引入的依赖包&#xff0c;后续由于某种原因而不需要该依赖包了&#xff0c;故已在pom文件中移除掉了该依赖包。 移除该依赖包之后&#xff0c;本地服务可正常构建和启动。 而测试环境却…

C语言 | Leetcode C语言题解之第504题七进制数

题目&#xff1a; 题解&#xff1a; char * convertToBase7(int num){if (num 0) {return "0";}bool negative num < 0;num abs(num);char * digits (char *)malloc(sizeof(char) * 32);int pos 0;while (num > 0) {digits[pos] num % 7 0;num / 7;}if…

cm211-1刷机教程镜像包

cm211-1刷机教程 包含镜像包酷看桌面 s905l3-l3b通用 镜像包&#xff1a;https://www.123684.com/s/WGAwjv-5tlv3 1.刷机教程 镜像为线刷镜像包&#xff0c;需要短接刷机 短接刷机&#xff0c;导入镜像包 开始即可。到100%就证明可以了。

四期书生大模型实战营(【入门岛】- 第4关 | 玩转HF/魔搭/魔乐社区)

文章目录 1. 任务介绍闯关任务 2. 平台介绍2.1. HF 平台2.1.1. HF的Transformers库介绍 2.2. GitHub CodeSpaces 和 Hugging Face Spaces 介绍。2.2.1. GitHub CodeSpaces2.2.2. Hugging Face Spaces2.2.3. 总结 3. 模型下载3.1. GitHub CodeSpaces使用3.1.下载internlm2_5-7b-…

MySQL任意版本安装卸载和数据库原理图绘制

MYSQL任意版本安装和卸载 安装&#xff1a; 1、解压文件 --- 不能出现中文路径 2、在解压目录&#xff08;安装目录&#xff09;下&#xff1a; 1>.创建data文件夹 2>.创建配置文件my.txt 然后修改成ini格式 3、修改配置文件 basedirD:\\mysql\\mysql-5.7.28-winx64…

006:看图软件ACDSeePhotoStudio2019安装教程

摘要&#xff1a;本文主要介绍看图软件ACDSee Photo Studio2019的安装流程。 一、软件概述 ACDSee Photo Studio是ACDSee公司开发的一款面向摄影师和图像编辑者的专业软件。它提供了全面的图像处理、管理和发布功能&#xff0c;帮助用户高效地浏览、编辑、分类和分享数字照片。…

新160个crackme - 084-slayer_crackme1

运行分析 点击check&#xff0c;提示注册失败 PE分析 ASM程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索到关键字符串发现注册文件reg.key 通过动态调试&#xff0c;获得计算机名称为’CONCEALBEAR’通过计算得到int_2 接下来有一个剪贴板判断&#xff0…

从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?

在工业检测领域&#xff0c;传统的检测手段常因效率低下、精度不足和潜在的安全风险而受到诟病。随着科技的不断进步&#xff0c;一种新兴的检测技术——红外热成像技术&#xff0c;正逐渐在该领域崭露头角。近期&#xff0c;小编对一款集成红外热成像技术的AORO A23防爆手机进…

【Linux系统】Ubuntu的简单操作

什么是 Ubuntu&#xff1f; Ubuntu&#xff08;乌帮图&#xff09;是一个非洲词汇&#xff0c;它的意思是“人性对待他人”或“群在故我在”。Ubuntu发行版将Ubuntu精神带到软件世界之中。 目前已有大量各种各样基于GNU/Linux的操作系统&#xff0c;例如:Debian,SuSE,Gentoo,R…

【热门主题】000010 深入 Vue.js 组件开发

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

【HarmonyOS Next】原生沉浸式界面

背景 在实际项目中&#xff0c;为了软件使用整体色调看起来统一&#xff0c;一般顶部和底部的颜色需要铺满整个手机屏幕。因此&#xff0c;这篇帖子是介绍设置的方法&#xff0c;也是应用沉浸式效果。如下图&#xff1a;底部的绿色延伸到上面的状态栏和下面的导航栏 UI 在鸿蒙…

Android 判断手机放置的方向

#1024程序员节&#xff5c;征文# 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 需求 老板&#xff1a;我有个手持终端&#xff0c;不能让他倒了&#xff0c;当他倒或者倾斜的时候要发出报警&#xff1b; 程序猿&#xff1a;我这..... 老板…

断点续传技术是什么?大型文件传输的新模式!

随着科技的不断进步&#xff0c;文件传输已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;传输大型文件时常常会遇到网络不稳定、传输中断等问题&#xff0c;导致传输失败或者重新传输。为解决这一问题&#xff0c;断点续传技术应运而生。 一、断点续传技术是什么…