【C++】模板-函数模板、类模板
文章目录
- 泛型编程
- 函数模板
- 函数模板的原理
- 函数模板的实例化
- 模板参数的匹配原则
- 类模板
- 类模板的定义格式
- 类模板的实例化
泛型编程
如果我们想要实现一个通用的交换函数,我们可以通过函数重载来实现,这些重载函数唯一的区别就是函数参数的类型不一样,虽然可以满足我们的需求,但是也有不好的地方:
1、重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数
2、代码的可维护性比较低,一个出错可能所有的重载都出错。
为了解决上述问题,C++提出了泛型编程,就是编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。
函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本,就是模板函数。
函数模板格式
template <typename T1,typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
template<typename Type>
Type Max(Type a, Type b)
{return a > b ? a : b;
}
typename是用来定义模板参数的关键字,也可以使用class,推荐使用typename,但是不能用struct代替class。
函数模板的原理
函数模板本身并不是一个函数,它只是一个蓝图,是编译器产生特定具体类型函数的模具,模板只是将本来应该由程序员做的那部分重复的工作交给了编译器来完成。
在编译器编译阶段,编译器会根据传入的实参类型来推演生成对应类型的模板函数。比如,我们判断double类型数据的Max时,编译器通过对实参类型的推演,将Type确定为double类型,然后会产生一份专门处理double类型数据的函数,对于其他类型也是如此,编译器帮我们完成了大量重复的工作。
函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化,函数模板的实例化分为:隐式实例化和显式实例化。
隐式实例化:让编译器根据实参类型推演模板参数的实际类型
template<typename Type>
Type Max(Type a, Type b)
{return a > b ? a : b;
}
void main()
{Max(10, 13.24);
}
Type无法确定自己是int类型还是double类型,这种情况下也不支持隐式转换,类型无法统一,产生了二义性,无法正常执行代码。
这种情况可以有下面的解决办法:
- 1、用户自己来强制转化
template<typename Type>
Type Max(Type a, Type b)
{return a > b ? a : b;
}
void main()
{Max((double)10, 13.24);
}
或者是:
template<typename Type>
Type Max(Type a, Type b)
{return a > b ? a : b;
}
void main()
{Max(10, (int)13.24);
}
上面这两种都是通过实参的推演得出Type的类型。
- 2、使用显式实例化:在函数后面的<>中指模板参数的实际类型
template<typename Type>
Type Max(Type a, Type b)
{return a > b ? a : b;
}
void main()
{Max<int>(10, 13.24);
}
明确告诉Max模板的参数类型是int,这个时候,传递的实参类型不满足int就会进行隐式类型,转化如果无法转换成功编译器将会报错。
- 3、增加模板参数的个数
template<typename Type1,typename Type2>
Type1 Max(Type1 a, Type2 b)
{return a > b ? a : b;
}
void main()
{cout << Max(10, 13.24) << endl;
}
这样编译器根据实参推演模板参数的实际类型就互相不打扰了,int匹配Type1,double匹配Type2,也能够解决问题。
模板参数的匹配原则
1、一个非模板函数可以和一个同名的模板函数同时存在,而且该模板函数还可以被实例化为这个非模板函数
template<typename Type>
Type Max(const Type &a, const Type &b)
{return a > b ? a : b;
}
int Max(const int &a, const int &b)
{return a > b ? a : b;
}
void main()
{cout << Max(10, 13) << endl;//调用非模板函数cout << Max<int>(10, 13) << endl;//调用模板函数实例化出的函数
}
2、对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数,不会从该函数模板实例化出一个模板函数。如果函数模板可以实例化出一个更加匹配的模板函数,那么将会选择实例化出一个模板函数来完成功能。
ype2 Max(const Type &a, const Type2 &b)
{return a > b ? a : b;
}
int Max(const int &a, const int &b)
{return a > b ? a : b;
}
void main()
{cout << Max(10, 13) << endl;//与非模板函数完全匹配,不需要函数模板实例化cout << Max(10, 13.98) << endl;//函数模板可以实力换出一个更加匹配的版本,编译器根据实参推演出参数实际类型,生成一个更匹配的函数
}
3、模板函数不允许自动类型转换,但是普通函数可以进行自动类型转换。
template<typename Type>
Type Max(const Type &a, const Type &b)
{return a > b ? a : b;
}
int Max(const int &a, const int &b)
{return a > b ? a : b;
}
void main()
{cout << Max(10, 13) << endl;cout << Max(10, 13.98) << endl;
}
这种情况下,都会调用非模板函数,起码可以保证正常执行。
类模板
类模板的定义格式
template<typename T1,typename T2,…typename T3>
class 类模板名
{
//类内成员定义
};
类模板中的函数都是函数模板,放在类外进行定义时,需要加模板参数列表。如下所示:
template<typename Type1, typename Type2 = int>//具备默认参数
class Seqlist
{public:void push_back(const Type1 &v);
public:enum{DEFAULT_SEQLIST_SIZE=8};
private:Type1 *base;size_t capacity;size_t size;
};
template<typename Type1,typename Type2>
void Seqlist<Type1,Type2>::push_back(const Type1 &v)
{}
类模板的实例化
类模板的实例化和函数模板的实例化不相同,类模板的实例化需要在类模板名字后面加上<>,然后实例化的类型放在<>中即可,函数模板可以推演类型,但是类模板必须明确类模板参数的类型,类模板名字不是真正的类,实例化的结果才是真正的类,,实例化之后的类才能够实例化出对象。
//Seqlist是类名,Seqlist<int>才是类型
Seqlist<int> s1;
Seqlist<double> s2;
【C++】模板-函数模板、类模板相关推荐
- C++函数模板和模板函数、类模板和模板类
这期间有涉及到函数模板与模板函数,类模板与模板类的概念 (类似于类与类对象的区别) 注意:模板类的函数声明和实现必须都在头文件中完成,不能像普通类那样声明在.h文件中,实现在.cpp文件中. 1.函数 ...
- 泛函编程—模板函数_类模板
函数业务逻辑一样,只是函数参数类型不同 函数模板的本质:类型参数化--泛型编程 语法: template <typename T> template <class T1,class ...
- 类模板,多种类型的类模板,自定义类模板,类模板的默认类型,数组的模板实现,友元和类模板,友元函数,类模板与静态变量,类模板与普通类之间互相继承,类模板作为模板参数,类嵌套,类模板嵌套,类包装器
1.第一个最简单的类模板案例 #include "mainwindow.h" #include <QApplication> #include <QPush ...
- C++中模板类中的成员函数以及模板函数在类外定义
在C++中,类中的成员函数可以在类外完成定义,从而显得类中的成员函数看起来简洁明了.但是模板类里的成员函数和模板函数与普通的成员函数在类外定义不同. 先定义一个模板类以及成员函数和模板函数: 接下我们 ...
- C++模板学习02(类模板)(类模板语法、类模板与函数模板的区别、类模板中的成员函数创建时机、类模板对象做函数参数、类模板与继承、类模板成员函数类外实现、类模板分文件编写、类模板与友元)
C++引用详情(引用的基本语法,注意事项,做函数的参数以及引用的本质,常量引用) 函数高级C++(函数的默认参数,函数的占位参数,函数重载的基本语法以及注意事项) C++类和对象-封装(属性和行为作为 ...
- c++模板---3(类模板碰到继承问题,类模板类外实现,类模板与友元函数)
类模板碰到继承问题 基类如果是模板类,必须让子类告诉编译器 基类中的T到底是什么类型 如果不告诉,那么无法分配内存,编译不过 利用参数列表class Child :public Base<int ...
- 模板 (函数模板语法 ,类模板与函数模板的区别,:函数模板案例,普通函数与函数模板的区别,普通函数与函数模板调用规则,模板的局限性,类模板分文件编写.cpp,Person.hpp,类模板与友元)
**01:函数模板语法: #include<iostream> using namespace std;//交换两个整型函数 void swapInt(int &a ,int &a ...
- C++(11):模板函数的默认模板参数
C++11支持在模板函数中使用默认的模板参数 #include <iostream> #include <typeinfo> using namespace std;templ ...
- 合同模板布局html,套打模板制作(合同类模板)
在制作模板前,需要了解以下几点 ① 布局表格是默认每页出现的(设置布局表格是否每页出现是不生效的),而当布局表格本身的行设置了行高自适应而产生的换页,默认为当前布局表格页还未结束,因此,这种情况产生的 ...
- C++类模板(二)用类模板实现可变长数组
#include <iostream> #include <cstring> using namespace std; template <class T> cla ...
最新文章
- 禁止蒙层底部页面跟随滚动
- 妥~阿里程序员常用的 15 款开发者工具
- java 批量存储_java I/O 批量插入保存文件
- minist读取一张图片
- react api_使用React流API将Akka流与rxJava结合在一起
- intent Filter
- python测试c语言代码_numpy C语言源代码调试(一)
- 敏感词过滤,并实现替换
- php mongodb长连接吗,PHP - MongoDB连接攻略
- 业务请求量膨胀的扩容技术实践
- zabbix 3.0 监控mysql_Zabbix-3.0.3 使用自带模板监控 MySQL
- java给xyz大小排序_Java Collection - 002 排序
- 个人使用unity3d过程中遇到的一些小问题集合之有时候在场景中创建光源会有一条虚线...
- 更新visual studio 报错The dependent package of ‘Microsoft.Net.PackageGroup.4.6.Redist‘
- 破解Kindle,轻松自定义字体
- 基于imx6ul下调试tlv320aic3x声卡
- AAMAS 2021 强化学习论文70篇(自整理)
- mac 运行android模拟器速度慢,Android模拟器速度慢 启动时间长的解决办法
- php aria2离线下载器,下载神器——Aria2,打造你自己的离线下载服务器
- matlab绘制香农定理曲线,基于matla对香农公式仿真.doc
热门文章
- 服务器阵列工作原理,服务器RAID技术基础了解一下
- Java中的char、Character和CharSequence的区别
- 2020届顺丰科技视觉算法工程师提前批面经
- Nginx部署单页面应用如何进行配置
- 反向题在测试问卷信效度_问卷信效度分析
- AliyunIoTSDK库使用问题和阿里云错误码解决
- C++实现线性顺序表的初始化,插入,删除,销毁,清空等功能
- E类(class E)功放的原理及设计
- 【正点原子STM32连载】第五十八章 USB虚拟串口(Slave)实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
- (二) CPU 性能测试 (不同品牌CPU算力比较)