C++入门之模板基础讲解

目录
  • 前言
  • 引入
  • 模板
  • 函数模板
  • 模板的匹配原则
  • 模板的显示调用
  • 类模板
    • 注意1
    • 注意2
  • 总结

前言

今天博主将要介绍的内容是–模板,他在C++中具有非常重要的位置.至于什么是模板呢?我们请看下面的章节.

引入

我们对交换函数Swap已经非常熟悉了,但是我们经常会遇到这样的一些事,比如,很多不同的数据类型进行交换,那么我们就需要写不同的重载Swap,如下:

#include <iostream>
using namespace std;
void Swap(int& a,int& b){
    int t  = a;
    a = b;
    b = t;
}
void Swap(double& a,double& b){
    double t = a;
    a = b;
    b = t;
}
int main()
{
    int a = 10,b = 20;
    double c = 1.2,d = 3.4;
    Swap(a,b);
    Swap(c,d);
    return 0;
}

可以看到,如果有必要,我们需要交换几种类型的数据,就必须写上几种重载Swap,这就导致非常的繁琐,因为我们对其交换逻辑太熟悉了,只是换了变量类型,那有什么办法可以解决呢?没错,这就是我们今天要讲的模板.

模板

概念:在生活中,博主举一个例子,假设你是一个手办厂家,现在你需要售出各种材料和颜色做的悟空手办,首先你需要的就是悟空的模型,然后按照这个模型使用不同的材料.这个模型就是我们在程序中的模板.

模板种类:

  • 函数模板
  • 类模板

函数模板

函数模板的格式:

template<class T1,class T2,...>
    return_val function_name (para1,para1,...)
{
}

打省略号的都是形参列表,表示参数量自由,我们现在知道了怎样使用函数模板,那试试写一个Swap模板:

template<class T>
void Swap (T& a,T& b)
{
    T t = a;
    a = b;
    b = a;
}

按照模板规范,我们写出来了Swap的模板,现在测试一下结果是否正确呢?

发现测试结果完全正确.

然后这里博主有个疑问,就是我们调用Swap时,编译器是执行的上面模板呢?还是执行的通过模板推演出来的函数呢?

答:通过模板推演出来的函数,因为C++提出模板是为了节省程序员的时间,我们所省略的工作,只是编译器替我们完成了.

也就是说,比如我们这样调用:

int main()
{
    int a = 10,b = 20;
    Swap(a,b);
    return 0;
}

那么编译器在底部会推演出一个如下函数,并执行:

void Swap(int& a,int& b){
    int t  = a;
    a = b;
    b = t;
}

模板的匹配原则

什么叫做模板的匹配原则呢?

就是说当既有定义出来的明确函数,同时又有模板,那么调用函数时候,执行的是哪一个?以下面为例:

void Swap(int& a,int& b){
    int t  = a;
    a = b;
    b = t;
}
template<class T>
void Swap (T& a,T& b)
{
    T t = a;
    a = b;
    b = a;
}
int main()
{
    int a = 10,b = 20;
    Swap(a,b);
    return 0;
}

匹配顺序为:

  • 如果有定义出来的函数,且类型完全匹配调用时实参类型,则执行定义出来的函数.
  • 如果定义出来的函数,不符合,则执行模板推演.

也就是说,上面的例子中,Swap调用的是我们定义出来的Swap,而不是模板.

模板的显示调用

上面讲解的模板使用,其实被称做隐式调用,现在,博主介绍一下显示调用.

显示调用格式:

function<Type1,Type2,..>(para1,para1,...);

也就是说,我们明确知道需要使用的什么类型,并且就想告诉编译器,我传给你的是什么类型,然后让编译器推演出该类型的函数.比如下面使用:

int a = 10,b = 20;
char c = 'a',d = 'b';
Swap<int>(a,b);  //告诉编译器我传的是int类型
Swap<char>(c,d);  //告诉编译器我传的是char类型

大家可能会问了,这有什么用呢?既然编译器会根据我们的调用情况进行推演,还进行显示调用不是多此一举吗?大家请看下面的代码:

template<class T>
void Swap (T& a,T& b)
{
    T t = a;
    a = b;
    b = a;
}
int main()
{
    int a = 10;
    double b = 23.22;
    Swap(a,b);         //这样调用编译器就会报错
    return 0;
}

像上面的调用方式,是不允许的,因为模板中只有一个T,但是我们传了两个类型,编译器根据模板将不知道T应该是啥类型,而解决上面的问题只有两种

  • 一是强制性转换类型,比如Swap(a,(int)b);
  • 二是显示使用模板,比如Swap<int>(a,b);

其次,博主讲解模板的显示调用还有一个目的就是为了引出下面的类模板.

类模板

类模板和函数模板相似,定义框架如下:

template <class T1,class T2,...>
    class class_name
    {
    };

我们对数据结构—栈,应该算比较了解,而对于经常刷力扣的伙伴来说,可能会发现栈不只是用来存储int类型,比如还有ListNode*等,那我们大概写一下其stack模板吧.

template <class T>
class Stack
{
public:
    Stack():data(new T*[10]),top(0),capacity(10) {}
    ~Stack()
    {
        delete[] data;
        top = capacity = 0;
    }
    void Push(T& a)
    {}
private:
    T* data;
    int top;
    int capacity;
};

然后我们定义Stack对象,但是对象应该存储的类型是什么呢?如果我们继续用最开始的隐式模板方法,发现完全实现不了,这也就是博主上面为何要讲解模板的显示调用,因为类模板只能通过显示调用实现,例子使用如下:

Stack <char> st1;      //定义一个存储char类型的栈
Stack <int> st2;       //定义一个存储int类型的栈
Stack <double> st3;    //定义一个存储double类型的栈

Stack并不是类,其只是一个模板,Stack <int>等才是类

注意1

类模板只是一个模板,他并不属于类.

注意2

当我们的模板类中的成员函数,在模板中声明,而在模板外定义时,需要加上模板参数列表,如下:

template <class T>
class Stack
{
public:
    void Push(T& a);
    bool empty();
private:
    T* data;
    int top;
    int capacity;
};
template <class T>
void Stack<T>:: Push(T& a)     //需要加上template <class T> ,且在Stack后面加上<T>
{}
template <class T>
void Stack<T>:: empty()        //需要加上template <class T> ,且在Stack后面加上<T>
{}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C++模板以及实现vector实例详解

    目录 函数模板 类模板 Vector实现 简单的类模板实现代码及测试: win msvc编译器的实现: 容器的空间配置器 运算符重载与迭代器实现 最终vector的实现代码 总结 函数模板 函数模板:是不进行编译的,因为类型还不知道 模板的实例化:函数调用点进行实例化 模板函数:才是要被编译器所编译的 模板类型参数:typyname/class 模板非类型参数:模板非类型形参的详细阐述 模板的实参推演:可以根据用户传入的实参的类型,来推导出模板类型参数的具体 模板的特例化(专用化)的实例化 模板

  • C++模板基础之函数模板与类模板实例详解

    泛型编程  如果让你编写一个函数,用于两个数的交换.在C语言中,我们会用如下方法: // 交换两个整型 void Swapi(int* p1, int* p2) { int tmp = *p1; *p1 = *p2; *p2 = tmp; } // 交换两个双精度浮点型 void Swapd(double* p1, double* p2) { double tmp = *p1; *p1 = *p2; *p2 = tmp; }  因为C语言不支持函数重载,所以用于交换不同类型变量的函数的函数名是不

  • 一篇文章带你了解C++模板编程详解

    目录 模板初阶 泛型编程 函数模板 函数模板概念 函数模板格式 函数模板的原理 函数模板的实例化 模板参数的匹配原则 类模板 类模板的定义格式 类模板的实例化 总结 模板初阶 泛型编程 在计算机程序设计领域,为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,人们发展的泛型及泛型编程技术.什么是泛型呢?实质上就是不使用具体数据类型(例如 int.double.float 等),而是使用一种通用类型来进行程序设计的方法,该方法可以大规模的减少程序代码的编写量,让程序员可以集中精力用于业

  • C++模板非类型形参的详细讲解

    前言 关于模板的非类型形参,网上有很多内容,C++primer只有大概一页的阐述,但是都不够清晰详细.下面我尽可能从自己的角度去给大家描述一下非类型形参的相关细节.如果想进一步理解非类型形参以及模板内容可以阅读C++template这本书,在4.1节,8.3.3节,13.2节都有相关解释. 模板除了定义类型参数,我们还可以在模板定义非类型参数. 什么是非类型形参?顾名思义,就是表示一个固定类型的常量而不是一个类型. 先举一个简单的例子(模板类与模板函数都可以用非类型形参) //例子1: temp

  • C++ Template 基础篇(一):函数模板详解

    Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第一部分. 为什么要有泛型编程 C++是一门强类型语言,所以无法做到像动态语言(python javascript)那样子,编写一段通用的逻辑,可以把任意类型的变量传进去处理.泛型编程弥补了这个缺点,通过把通用逻辑设计为模板,摆脱了类型的限制,提供了继承机制以外的另一种抽象机制,极大地提升了代码的可重用性. 注意:模板定义本身不参与编译,而是编译器根据模板的用户使

  • C++入门之模板基础讲解

    目录 前言 引入 模板 函数模板 模板的匹配原则 模板的显示调用 类模板 注意1 注意2 总结 前言 今天博主将要介绍的内容是–模板,他在C++中具有非常重要的位置.至于什么是模板呢?我们请看下面的章节. 引入 我们对交换函数Swap已经非常熟悉了,但是我们经常会遇到这样的一些事,比如,很多不同的数据类型进行交换,那么我们就需要写不同的重载Swap,如下: #include <iostream> using namespace std; void Swap(int& a,int&

  • Django零基础入门之模板变量详解

    引言: 我们在页面上会看到,谁登录的就会显示谁的信息,那么这个页面上的变量信息是怎样实现的呢? 这就是本文要讲述的内容--Django中的模板变量! 1.模板变量! 可以在前端页面中使用模板变量来取数据库中的数据,实现前端页面数据动态显示. (1)模板变量使用规则:(在HTML模板中使用!) 语法: {{ 变量名 }} 命名由字母和数字以及下划线组成,不能有空格和标点符号 可以使用字典.类对象.方法.函数.列表.字符串 不要和python或django关键字重名 注意: 如果data是一个字典,

  • C++类模板与函数模板基础详细讲解

    目录 函数模板 类模板 总结 函数模板 当我们想要定义一个可以支持泛型的函数时,就要采用函数模板的方式了.所谓泛型就是可以支持多种类型的操作,比如我们定义一个compare操作,他可以根据传递给他的参数类型动态调用对应的函数版本,实现多种类型的比较. template <typename T> int compare(const T &v1, const T &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1;

  • Vue零基础入门之模板语法与数据绑定及Object.defineProperty方法详解

    目录 初识vue 模板语法 插值语法 指令语法 数据绑定 单向绑定 双向绑定 el和data的两种写法 el data Object.defineProperty方法 事件处理 事件修饰符 键盘事件 定义命名(不常用) 初识vue vue工作时,必须先创建Vue实例,且要传入一个配置对象 容器内的代码依然符合html规范,混入了一些特殊的Vue语法 <div id="root"> <h1>hello,{{name}}</h1> </div>

  • Java 类与对象超基础讲解

    目录 什么是面向对象 面向过程与面向对象 类与对象的使用 类与对象的使用与说明 对象的初始化 this的使用 构造方法 this可以调用本类的构造方法 什么是面向对象 Java语言是一个纯面向对象的语言,面向对象的语言不仅只有Java,包括C++,PHP等 面向对象的编程思想简称 OOP(Object Oriented Programming),其基本特点就是封装,继承和多态. 面向过程与面向对象 想要弄清楚什么是面向对象,首先需要知道两者的区别 面向过程更注重程序的每一个步骤,用相应的函数来实

  • Spring的连接数据库以及JDBC模板(实例讲解)

    前言 今天介绍的是关于Spring的数据库连接以及Jdbc模板的相关API方法,虽然在学习了hibernate之后,会知道实现数据库连接一般都是使用hibernate等持久化框架来实现的.但是,很多时候一些涉及到事务的东西使用这些框架并不能够实现,所以我们还需要结合spring来实现相关的需要. 一.创建工程.导包 要想使用Spring的jdbc模板前,还需要导入相关的jar包: 二.进行相关的bean的创建以及工具类的编写 2.1在数据库中创建了两张表,使用spring的jdbcTemplat

  • JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)

    说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象JS基础讲解,工厂模式.构造函数模式.原型模式.混合模式.动态原型模式>,接下来讲一般通过那些方法完成JavaScript的继承. 原型链 JavaScript中实现继承最简单的方式就是使用原型链,将子类型的原型指向父类型的实例即可,即"子类型.prototype = new 父类型();&qu

  • jquery tmpl模板(实例讲解)

    之前用模板渲染都是用angular,无意间发现了jquery tmpl这种轻量级,其文档在这里 官方解释对该插件的说明:将匹配的第一个元素作为模板,render指定的数据,签名如下: .tmpl([data,][options]) 其中参数data的用途很明显:用于render的数据,可以是任意js类型,包括数组和对象.options一般情况下都是选项了,官方指出,此处的options是一个用户自定义的键值对的map,继承自tmplItem数据结构,适用于模板render动作期间. 在这里可以下

  • jQuery插件imgAreaSelect基础讲解

    关于ImgAreaSelect,  是一jQuery插件,它支持用户通过鼠标拖曳选择图片的一部分,如图片拖曳.图片编辑等~~来具体看一下 1.先下载imgAreaSelect插件 下载地址: 英文:http://odyniec.net/projects/imgareaselect/ 中文:http://www.css88.com/EasyTools/javascript/jQueryPlugin/imgAreaSelect/index.html 在头部引用: <link rel="styl

  • Python爬虫入门有哪些基础知识点

    1.什么是爬虫 爬虫,即网络爬虫,大家可以理解为在网络上爬行的一直蜘蛛,互联网就比作一张大网,而爬虫便是在这张网上爬来爬去的蜘蛛咯,如果它遇到资源,那么它就会抓取下来.想抓取什么?这个由你来控制它咯. 比如它在抓取一个网页,在这个网中他发现了一条道路,其实就是指向网页的超链接,那么它就可以爬到另一张网上来获取数据.这样,整个连在一起的大网对这之蜘蛛来说触手可及,分分钟爬下来不是事儿. 2.浏览网页的过程 在用户浏览网页的过程中,我们可能会看到许多好看的图片,比如 http://image.bai

随机推荐