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

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

 


目录

💯前言

💯泛型编程

💯函数模板

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】 

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

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

相关文章

社交媒体视频素材平台推荐

在内容创作日益重要的今天&#xff0c;社交媒体视频素材的需求不断增加。适合各种平台的视频素材不仅可以提升内容质量&#xff0c;还能吸引更多观众。以下是一些推荐的社交媒体视频素材平台&#xff0c;帮助你找到适合的资源。 蛙学网 蛙学网 是一个专注于社交媒体视频素材的平…

C# 标准绘图控件 chart 多 Y 值的编程应用

C# 标准绘图控件 chart 多 Y 值的编程应用 1、前言2、声明标准绘图控件 chart 命名空间3、使用绘图控件 chart3.1、在窗体中拖入绘图控件 chart &#xff0c;拖入绘图控件 chart 最简单实用。3.2、在语句中声明加入&#xff0c;但要将 控件和其组件加入窗体或其它容器很麻烦&am…

2025 - AI人工智能药物设计 - 中药网络药理学和毒理学的研究

中药网络药理学和毒理学的研究 TCMSP&#xff1a;https://old.tcmsp-e.com/tcmsp.php 然后去pubchem选择&#xff1a;输入Molecule Name 然后进行匹配&#xff1a;得到了smiles 再次通过smiles&#xff1a;COC1C(CC(C2C1OC(CC2O)C3CCCCC3)O)O 然后再次输入&#xff1a;http…

尚硅谷-react教程-求和案例-数据共享(下篇)-完成数据共享-笔记

#1024程序员节&#xff5c;征文# public/index.html <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>redux</title></head><body><div id"root"></div></body> </html&…

Vuex的基础

文章目录 vuex概述构建vuex[多组件数据共享]环境创建一个空仓库ps.创建仓库时遇到的错误 核心概念 - state状态核心概念 - mutations辅助函数 - mapMutations 核心概念 - actions辅助函数 - mapActions 核心概念 - getters核心概念 - 模块module&#xff08;进阶语法&#xff0…

Python(pandas库2)

DateFrame的添加 上文中DateFrame的增加中&#xff0c;因版本弃置append函数 如果你想要向 DataFrame 添加一行&#xff0c;建议的方法是首先创建一个新的 DataFrame 来表示这行数据&#xff0c;然后使用 pd.concat() 函数来合并它们。 concat 语法&#xff1a; objs: 要连…

基于协同过滤算法的个性化课程推荐系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

JDBC: Java数据库连接的桥梁

什么是JDBC&#xff1f; Java数据库连接&#xff08;Java Database Connectivity&#xff0c;简称JDBC&#xff09;是Java提供的一种API&#xff0c;允许Java应用程序与各种数据库进行交互。JDBC提供了一组标准的接口&#xff0c;开发者可以利用这些接口执行SQL语句、处理结果集…

「C/C++」C++ STL容器库 之 std::multiset 键的集合容器

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「C/C」C/C程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasoli…

腾讯云跨AZ部署FortigateHA备忘录

随时保存配置 config system globalset admintimeout 480set alias "FortiGate-VM64-KVM"set gui-auto-upgrade-setup-warning disableset hostname "FG-Slave"set revision-backup-on-logout enableset revision-image-auto-backup enableset timezone &…

【 thinkphp8 】00006 启动 内、外置服务器

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

Java学习Day53:铲除紫云山金丹原料厂厂长(手机快速登录、权限控制)

1.手机快速登录 手机快速登录功能&#xff0c;就是通过短信验证码的方式进行登录。这种方式相对于用户名密码登录方式&#xff0c;用户不需要记忆自己的密码&#xff0c;只需要通过输入手机号并获取验证码就可以完成登录&#xff0c;是目前比较流行的登录方式。 前端页面&…

centos7.x安装openCV 4.6.0版本

## 从源代码编译安装 1.更新系统 sudo yum update -y 2.安装依赖项 sudo yum groupinstall "Development Tools" sudo yum install cmake gcc-c git libjpeg-turbo-devel libpng-devel libtiff-devel libwebp-devel openexr-devel gstreamer1-plugins-base-devel…

iTerm2 保持SSH远程连接

1、保持SSH远程连接的稳定&#xff0c;防止因闲置时间过长而断开连接 When idle, send ASCII code 35 every 60 seconds每60秒 输入# 2、客户端设置保持活动 设置客户端每隔60秒发送一次保活信号&#xff0c;总共尝试3次。 vim ~/.ssh/configHost *ServerAliveInterval 60…

uniapp 底部导航栏tabBar设置后不显示的问题——已解决

uniapp 底部导航栏tabBar设置后不显示的问题——已解决 网上找了一堆解决办法&#xff0c;挨个对着试吧 解决办法一&#xff1a;tabBar里的list第一项和page中的第一项要相同&#xff0c;确实就能显示了。但是问题来了&#xff0c;page中的第一项是入口页&#xff0c;那就意味…

鲸鱼优化算法(Whale Optimization Algorithm, WOA)原理与MATLAB例程

鲸鱼优化算法&#xff08;Whale Optimization Algorithm, WOA&#xff09;是一种基于鲸鱼捕食行为的智能优化算法。它模拟了座头鲸在狩猎时的“气泡网”捕食策略。 文章目录 1.适应度函数2. 更新公式2.1 突袭行为2.2 螺旋更新3.线性递减参数4. 边界处理 MATLAB 实现示例代码说明…

HarmonyOS 5.0应用开发——Navigation实现页面路由

【高心星出品】 文章目录 Navigation实现页面路由完整的Navigation入口页面子页面 页面跳转路由拦截其他的 Navigation实现页面路由 Navigation&#xff1a;路由导航的根视图容器&#xff0c;一般作为页面&#xff08;Entry&#xff09;的根容器去使用&#xff0c;包括单页面&…

前端构建工具vite的优势

1. 极速冷启动 Vite 使用原生 ES 模块 (ESM) 在开发环境下进行工作。相比于传统构建工具需要打包所有的文件&#xff0c;Vite 只在浏览器请求模块时动态加载所需的文件。无打包冷启动&#xff1a;无需预先打包&#xff0c;项目启动非常快&#xff0c;尤其对于大型项目效果更明…

Arduino Uno 同时控制多路舵机

Arduino Uno同时控制4个舵机 舵机可以在0~180度内指定角度的控制。常用于航模、机器人、遥控玩具等物品,然而,很多时候要一次性控制多个舵机,今天以控制4个舵机为例进行说明 接线方式如下图: 舵机的信号线分别接A0,A1,A2,A3。控制舵机从0旋转到180度,再由180度旋转到0度,…

基于NERF技术重建学习笔记

NeRF&#xff08;Neural Radiance Fields&#xff09;是一种用于3D场景重建的神经网络模型&#xff0c;能够从2D图像生成逼真的3D渲染效果。它将场景表征为一个连续的5D函数&#xff0c;利用了体积渲染和神经网络的结合&#xff0c;通过学习光线穿过空间时的颜色和密度来重建场…