当前位置: 首页 > news >正文

C++中的利器——模板

前文

本文主要是讲解一下C++中的利器——模板,相信铁子们在学完这一节后,写代码会更加的得心应手,更加的顺畅。

一,泛型编程

想要学习模板,我们要先了解为什么需要模板,我们可以看看下面这个程序。
int add(int& a, int& b)
{
    return a + b;
}
double add(double& a, double& b)
{
    return a + b;
}
看看上面的程序,通过函数重载,我们实现了不同类型的add函数,但是否有些麻烦呢,这些函数只是类型不同,而每增加一个新类型我们就要在写一个函数,而且一个出错,可能所有的函数都出错。
而我们C++的老祖宗也想到了这个问题,于是 模板就应运而生了。
通过 模板来实现我们的需求可以称为 泛型编程
泛型编程编写与类型无关的通用代码,是代码复用的一种手段。模型是泛型编程的基础

二,函数模板

2.1 函数模板的概念

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

2.2函数模板格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
template<typename A>
A add(A& a, A& b)
{
    return a + b;
}
注意:typename是用来定义模板参数关键字,也可以使用 class(切记:不能使用struct代替class)

2.3 函数模板的原理

函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后 只是一个对函数功能框架的描述,当它具体执行时, 将根据传递的实际参数决定其功能。 所以其实就是将我们重复做的事情交给了编译器,当然要是怕累着编译器也可以自己实现,haha。
template<typename A>
A add(A& a, A& b)
{
    return a + b;
}
int main()
{
    int a = 1, b = 2;
    add(a, b);

    double c = 3.3, d = 4.4;
    add(c, d);

    return 0;
}
如以上程序调用方式如下
当我们调试的时候调到反汇编,我们可以发现int型的和double型所调用的函数是不一样的,由此我们也可以论证, 编译器根据模板创建出对应函数以供使用,在这个过程中模板起到了一个蓝图的作用,而具体的建造材料则由我们传过去的参数决定。
而这个建造的过程一般是在 编译器编译阶段,对于函数模板的使用 ,编译器会根据传入的实参类型来推演出对应类型的函数以供使用。比如:当用double类型使用函数模板add时,编译器通过对参数类型的推演,将A确定为double型创造函数。

2.4 函数模板的实例化

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

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

template<typename A>
A add(A& a, A& b)
{
    return a + b;
}
int main()
{
    //下面两个是比较典型的隐式实例化
    int i1 = 1, i2 = 2;
    add(i1, i2);

    double d1 = 3.3, d2 = 4.4;
    add(d1, d2);
    //那么下面这种情况呢
    //add(i1,d1) add(i2,d2)
    //这种情况下,编译器会根据实参i1将A推演为int
    //通过实参d1将A推演为double型
    //此时编译器不知道用那个,就会报错
    //那么怎么解决这种情况呢
    //1.强制转化
    add(i1, (int)d1);
    add((double)i2, d2);
    //2.显示实例化
    return 0;
}

2.显示实例化:在函数名后的<>中指定模板参数的实际类型

2.5 模板参数的匹配规则

  1. 一个非模板函数可以和一个同名函数模板同时出现,而且该函数模板还可以被实例化成这个非模板函数

int add(int& a, int& b)
{
    return a + b;
}
template<typename A>
A add(A& a, A& b)
{
    return a + b;
}
int main()
{
    add(1, 2);
    //此时会优先调用非模板函数
    //因为跳过模板实例化的过程效率更高
    
    add(int)(1, 2);//通过实例化模板,
    //也可以实例化出这个非模板函数
    return 0;
}
  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

int add(int& a, int& b)
{
    return a + b;
}
template<typename A>
A1 add(A1& a, A2& b)
{
    return a + b;
}
int main()
{
    add(1, 2);//完全匹配非模板函数
    //不会在进行模板实例化,而是直接选择非模板函数
    add(1, 1.1);//与非模板函数不匹配,
    //模板函数会根据参数生成更加匹配的函数
    return 0;
}
  1. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

三,类模板

3.1 类模板的定义格式

定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
    // 类内成员定义
};
template<class A>
class Stack
{
public:
    Stack(int capaicty = 4)
    {
        _a = new A[capaicty];
        _size = 0;
        _capaicty = capaicty;
    }
    ~Stack()
    {
        delete[] _a;
        _size = _capaicty = 0;
    }
private:
    A* _a;
    int _size;
    int _capaicty;
};
int main()
{
    //通过类模板,我们可以同时创建int和double类型的栈
    Stack <int>st1;
    Stack <double>st2;
    return 0;

}

3.2 类模板的实例化

类模板实例化与函数模板实例化不同, 类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类

总结

学习过模板后,C++的学习也会进入一段蜜月期,因为之后我们会接着学习stl库,这将大大提高我们C++代码的编写效率。

相关文章:

  • Python绘图
  • 【Linux】-- 基本指令
  • 核心 Android 调节音量的过程
  • 微信小程序this指向问题
  • synchronized从入门到踹门
  • 运算符——“Python”
  • Nginx的搭建与核心配置
  • Stream——数字类型的字符串排序
  • FISCO BCOS(二十八)———使用java SDK与区块链交互
  • <JVM上篇:内存与垃圾回收篇>13 - 垃圾回收器
  • 海思SD3403/SS928V100开发(6)单路GMSL-MIPI-YUV相机视频输入调试
  • 计算机SCI期刊投稿,除了投稿信,还要做什么准备? - 易智编译EaseEditing
  • 监控易网络管理:网络流量分析
  • PCB布线及后仿真验证过程(干货满满,建议收藏)
  • Activty启动到显示的过程[二]
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • Elasticsearch 参考指南(升级前重新索引)
  • JAVA 学习IO流
  • JS实现简单的MVC模式开发小游戏
  • mac修复ab及siege安装
  • mysql 数据库四种事务隔离级别
  • python3 使用 asyncio 代替线程
  • SpiderData 2019年2月23日 DApp数据排行榜
  • SSH 免密登录
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • 高程读书笔记 第六章 面向对象程序设计
  • 好的网址,关于.net 4.0 ,vs 2010
  • 蓝海存储开关机注意事项总结
  • 前端之React实战:创建跨平台的项目架构
  • 如何设计一个比特币钱包服务
  • 使用parted解决大于2T的磁盘分区
  • 一个完整Java Web项目背后的密码
  • 用jQuery怎么做到前后端分离
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • # include “ “ 和 # include < >两者的区别
  • (LeetCode 49)Anagrams
  • (二)linux使用docker容器运行mysql
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转) Android中ViewStub组件使用
  • (转)菜鸟学数据库(三)——存储过程
  • (转)视频码率,帧率和分辨率的联系与区别
  • ***测试-HTTP方法
  • ./configure、make、make install 命令
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数
  • .NET序列化 serializable,反序列化
  • .php文件都打不开,打不开php文件怎么办
  • /dev/VolGroup00/LogVol00:unexpected inconsistency;run fsck manually
  • @Autowired自动装配
  • @RequestMapping-占位符映射
  • @SuppressWarnings注解
  • @Transactional类内部访问失效原因详解
  • [].shift.call( arguments ) 和 [].slice.call( arguments )