iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++模板编程的示例分析
  • 685
分享到

C++模板编程的示例分析

2023-06-25 12:06:19 685人浏览 安东尼
摘要

这篇文章主要为大家展示了“c++模板编程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++模板编程的示例分析”这篇文章吧。模板初阶泛型编程在计算机程序设计领域,为了避免因数据类型的不

这篇文章主要为大家展示了“c++模板编程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++模板编程的示例分析”这篇文章吧。

    模板初阶

    泛型编程

    在计算机程序设计领域,为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,人们发展的泛型及泛型编程技术。什么是泛型呢?实质上就是不使用具体数据类型(例如 int、double、float 等),而是使用一种通用类型来进行程序设计的方法,该方法可以大规模的减少程序代码的编写量,让程序员可以集中精力用于业务逻辑的实现。泛型也是一种数据类型,只不过它是一种用来代替所有类型的“通用类型”

    我们通常如何实现一个通用的交换函数呢?

    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;}......

    Swap函数能实现各种类型的变量交换,但是只要类型不同就需要重新写一个

    使用函数重载虽然可以实现,但是有一下几个不好的地方:

    • 重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数

    • 代码的可维护性比较低,一个出错可能所有的重载均出错,那能否告诉编译器一个模版,让编译器根据不同的类型利用该模版来生成代码呢?

    可以的,C++语法中有了模板:

    函数模板

    函数模板概念

    所谓函数模板,实际上是建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。 这个通用函数就称为 函数模板(Function Template) 。函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

    函数模板格式

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

    template<typename T>//或者 template<class T>void Swap(T& x1, T& x2){    T temp = left;    left = right;    right = temp;}

    T1,T2等等是什么类型现在也不确定,一会用的时候才能确定

    注意:

    typename是用来定义模板参数关键字,也可以使用class

    函数模板的原理

    函数模板本身并不是函数,是编译器根据调用的参数类型产生特定具体类型函数的模具,所以其实模板就是将本来应该我们做的重复的事情交给了编译器,我们看下面的例子:

    template<class T>void Swap(T& x, T& y){T temp = x;x = y;y = temp;}int main(){int a = 1;int b = 2;Swap(a, b);char A = 'a';char B = 'b';Swap(A,B);return 0;}

    C++模板编程的示例分析

    在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然
    后产生一份专门处理int类型的代码,对于字符类型也是如此。

    然而当我们在写了函数时,不会进入模板函数里,没有写具体的函数时,就会进入模板函数里,我们看下面的例子:

    void Swap(int& x, int& y){int temp = x;x = y;y = temp;}template<class T>void Swap(T& x, T& y){T temp = x;x = y;y = temp;}int main(){int a = 1;int b = 2;Swap(a, b);char A = 'a';char B = 'b';Swap(A,B);return 0;}

    我们进行调式:

    C++模板编程的示例分析

    我们可以看到int类型的交换函数我们写了,调用时调用的是我们写的,而char类型的我们没写,就用了模板。

    那么这里调用的是模板函数吗?

    不是的,实际上这里会有两个过程

    模板推演,推演T的具体类型是什么

    推演出T的具体类型后实例化生成具体的函数

    上面的代码实例化生成了下面的函数:

    void Swap(char& x, char& y){char temp = x;x = y;y = temp;}

    真正调用的还是两个函数,但是其中的一个函数不是我们自己写的,而是我们给了编译器一个模板,然后编译器进行推演在编译之前实例化生成三个对应的函数,模板是给编译器用的,编译器充当了写函数的工具

    C++模板编程的示例分析

    可以看到这里是调用了Swap<char>函数

    在C++当中,其实内置类型也可以像自定义类型那样这样初始化:

    int a(1);int(2);//匿名

    C++模板编程的示例分析

    void Swap(T& x1, T& x2){    T temp(x1);    x1 = x2;    x2 = x1;}

    所以模板还可以这样写,可以使内置类型和自定义类型兼容:

    void Swap(T& x1, T& x2){    T temp(x1);    x1 = x2;    x2 = x1;}

    我们来具体看一看函数模板的实例化:

    函数模板的实例化

    用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

    隐式实例化:让编译器根据实参推演模板参数的实际类型

    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);    Add(d1, d2);// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化    Add(a1, d2);    return 0;}

    该语句是不能够通过编译的,因为在编译期间,当编译器看到该实例化时,用a1去推T是int,而用d2去推是double,但是模板参数列表里只有一个T,编译器不能明确该T是int还是double,T是不明确的,所以编译器会报错

    那么怎么处理呢?

    解决方式:

    1、调用者自己强制转换

    //实参去推演形参的类型Add(a1, (int)d2);Add((double)a1,d2);

    这里可以将d2先强制类型转换,然后再进行推演;或者将a1先强制类型转换再进行推演

    2、使用显式实例化

    //实参不需要去推演形参的类型,显式实例化指定T的类型Add<int>(a1, d2);Add<double>(a1,d2);

    这种方式是显式实例化指定T的类型

    显式实例化在哪种场景可用呢?看下面的这种场景:

    class A{    A(int a=0):_a(a)    {}private:    int _a;};template<class T>T func(int x){    T a(x);    return a;}int main(){    func<A>(1);    func<int>(2);    return 0;}

    有些函数模板里面参数中没用模板参数,函数体内才有用到模板参数,此时就无法通过参数去推演T的类型,这时只能显示实例化

    上面我们提了一点模板参数的匹配原则,下面我们具体看看模板参数的匹配原则:

    模板参数的匹配原则

     一个非模板函数可以和一个同名的函数模板同时存在,此时如果调用地方参数与非模板函数完全匹配,则会调用非模板函数

    int Add(int left, int right){return left + right;}// 通用加法函数template<class T>T Add(T left, T right){return left + right;}int main(){    Add(1,2);//调用自己的函数    return 0;}

    Add(1,2)参数是int类型,而我们有现成的int参数的Add函数,所以有现成的就用现成的,编译器也会偷懒

    那么如果我们想让这里调用必须用模板呢?显式实例化:

    Add<int>(1,2);

    这样编译器就强制会用模板去实例化函数

    一个非模板函数可以和一个同名的函数模板同时存在,此时如果调用地方参数与非模板函数不完全匹配,则会优先使用模板实例化函数

    int Add(int left, int right){return left + right;}// 通用加法函数template<class T>T Add(T left, T right){return left + right;}int main(){    Add(1.1,2.2);//使用模板实例化函数    return 0;}

    模板匹配原则总结:

    有现成完全匹配的,那就直接调用,没有现成调用的,实例化模板生成,如果有需要转换类型才能匹配的函数(也就是不完全匹配),那么它会优先选择去实例化模板生成。

    优先级:

    完全匹配>模板>转换类型匹配

    类模板

    类模板的定义格式

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

    我们来看一个类模板的使用场景:

    typedef int STDateType;class Stack{private:    STDateType* _a;    int _top;    int _capacity;};int main(){    Stack st1;    Stack st2;    return 0;}

    这是我们定义的栈数据结构,我们创建了两个栈对象,但是现在st1和st2的存储数据的类型都是int,要是想转换数据类型呢?

    typedef double STDateType;

    我们这样就转换了,但是我们要是想st1为int,st2为double呢:

    Stack st1;//intStack st2;//double

    此时需要写多个类,名字还得不一样,如下:

    typedef int STDateType1;typedef double STDateType2;class IntStack{private:    STDateType1* _a;    int _top;    int _capacity;};class DoubleStack{private:    STDateType2* _a;    int _top;    int _capacity;};

    这样太麻烦了,那么什么办法可以解决呢?类模板可以解决:

    //类模板template<class T>class Stack{private:    T* _a;    int _top;    int _capaticy;};int main(){    //类模板的使用都是显式实例化    Stack<double> st1;    Stack<int> st2;    return 0;}

    注意:Stack不是具体的类,是编译器根据被实例化的类型生成具体类的模具

    类模板的实例化

    //类模板template<class T>class Stack{public:    Stack(int capacity = 4)        :_a(new T(capacity))         ,_top(0)         ,_capacity(capacity)        {}    ~Stack()    {        delete[] _a;        _a = nullptr;        _top = _capacity = 0;    }    void Push(const T& x)    {        //...    }private:    T* _a;    int _top;    int _capaticy;};int main(){    //类模板的使用都是显式实例化    Stack<double> st1;    Stack<int> st2;    return 0;}

    注意:类模板的使用都是显式实例化

    假设我们想类里面声明和类外面定义成员函数呢?

    //类模板template<class T>class Stack{public:    Stack(int capacity = 4)        :_a(new T(capacity))         ,_top(0)         ,_capacity(capacity)        {}    ~Stack()    {        delete[] _a;        _a = nullptr;        _top = _capacity = 0;    }    //假设我们想类里面声明和定义分离呢?    void Push(const T& x);private:    T* _a;    int _top;    int _capaticy;};//在类外面定义template<class T>void Stack<T>::Push(const T& x);{    //...}int main(){    //类模板的使用都是显式实例化    Stack<Treenode*> st1;    Stack<int> st2;    return 0;}
    //在类外面定义template<class T>void Stack<T>::Push(const T& x);{    //...}

    在类外面定义我们必须要加模板的关键字,以及需要在实现的函数前面表明域Stack<T>。普通类,类名就是类型,对于类模板,类名不是类型,类型是Stack<T>,需要写指定

    注意:

    模板不支持把声明写到.h,定义写到.cpp,这种声明和定义分开实现的方式,会出现链接错误

    以上是“C++模板编程的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网其他教程频道!

    --结束END--

    本文标题: C++模板编程的示例分析

    本文链接: https://www.lsjlt.com/news/304627.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • C++模板编程的示例分析
      这篇文章主要为大家展示了“C++模板编程的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C++模板编程的示例分析”这篇文章吧。模板初阶泛型编程在计算机程序设计领域,为了避免因数据类型的不...
      99+
      2023-06-25
    • C++模板重载的示例分析
      本篇文章为大家展示了C++模板重载的示例分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.重载模板函数模板可以使得同一个函数对不同类型使用,非常地方便。但有的时候类型不同,只是通过模板是没办法解...
      99+
      2023-06-22
    • Vue3模板编译优化的示例分析
      小编给大家分享一下Vue3模板编译优化的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!编译入口了解过 Vue3 的同学肯...
      99+
      2022-10-19
    • java模板模式的示例分析
      这篇文章主要介绍java模板模式的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Java设计模式-模板模式什么是模板模式?模板模式,顾名思义,就是通过模板拓印的方式。定义模板,就是定义框架、结构、原型。定义一...
      99+
      2023-06-20
    • C#异步编程的示例分析
      小编给大家分享一下C#异步编程的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!异步编程在处理并发方面被使用的越来越多,之所以说上面一句话,是为了区分多线程...
      99+
      2023-06-17
    • C++模板>>编译问题举例分析
      本篇内容主要讲解“C++模板>>编译问题举例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++模板>>编译问题举例分析”吧!在编译理论中,通常将编译过程抽象为5个主...
      99+
      2023-06-17
    • C++模板使用实例分析
      这篇文章主要介绍了C++模板使用实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++模板使用实例分析文章都会有所收获,下面我们一起来看看吧。非类型模板参数模板参数分类类型形参与非类型形参。类型形参:出现...
      99+
      2023-06-30
    • C#单例模式的示例分析
      这篇文章给大家分享的是有关C#单例模式的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。单例模式也是创建型模式的一种,也是23种设计模式中比较简单的一种。见名思意,在整个软件系统中,只有某个类型的一个对象,...
      99+
      2023-06-29
    • C++ 类模板与成员函数模板示例解析
      目录类模板类模板与成员函数模板的区别类模板 前面以函数模板为例,介绍了具体化与实例化。那么对于类模板,有什么不同呢? 类包括成员变量和成员函数,他们都可以包含类模板的模板参数。而成...
      99+
      2023-01-03
      C++ 类模板成员函数模板 C++ 类模板成员函数模板
    • c#中异步编程的示例分析
      这篇文章给大家分享的是有关c#中异步编程的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、什么算异步?  广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的。在面向服务的系...
      99+
      2023-06-14
    • es6模板字符串的示例分析
      小编给大家分享一下es6模板字符串的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体如下作为前端开发者避免不了根据后台...
      99+
      2022-10-19
    • CSS5初始化模板的示例分析
      这篇文章给大家分享的是有关CSS5初始化模板的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。 CSS5初始化模板席卷了GBK编码内容和UTF-8编码内容的两个编码模板。...
      99+
      2022-10-19
    • python中不同模板的示例分析
      这篇文章将为大家详细讲解有关python中不同模板的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、long(...
      99+
      2023-06-14
    • PHP中模板方法模式的示例分析
      小编给大家分享一下PHP中模板方法模式的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!模板方法模式,也是我们经常会在不经意间有会用到的模式之一。这个模式是...
      99+
      2023-06-20
    • C++11模板函数的默认模板参数举例分析
      这篇文章主要介绍“C++11模板函数的默认模板参数举例分析”,在日常操作中,相信很多人在C++11模板函数的默认模板参数举例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++11模板函数的默认模板参数举...
      99+
      2023-06-19
    • C#策略模式的示例分析
      小编给大家分享一下C#策略模式的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!策略模式所谓策略其实就是做一件事情有很多很多的方法,比如说一个商场要搞促销,...
      99+
      2023-06-29
    • ES6中模板字符串的示例分析
      这篇文章主要为大家展示了“ES6中模板字符串的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“ES6中模板字符串的示例分析”这篇文章吧。模板字符串(tem...
      99+
      2022-10-19
    • springboot中Thymeleaf模板引擎的示例分析
      这篇文章给大家分享的是有关springboot中Thymeleaf模板引擎的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。模板引擎springboot我们目前是以jar包的形式打包,实际上我们之前是打成w...
      99+
      2023-06-29
    • Python中Django模板系统的示例分析
      这篇文章主要为大家展示了“Python中Django模板系统的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Python中Django模板系统的示例分析”这篇文章吧。设置模板路径在dja...
      99+
      2023-06-25
    • C++程序的示例分析
      小编给大家分享一下C++程序的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!我们先来看一段C++的示例代码:// my first&n...
      99+
      2023-06-25
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作