泛型编程 模板1
2016-06-19 02:35
239 查看
一 泛型编程
首先来看一段实现加法函数的代码
这个函数现在只能接收int类型的数据,如果我们想让他成为通用的加法函数该怎么办呢?
根据我们在C++前一段时间所学的知识,有三种方法来解决这个问题,但是这些方法也有 各自不同的问题
函数重载
缺点:
1)代码复用率太低,只要有新类型出现就要再写一个像对应的函数,而这些函数的 函数体都相同
2)如果函数只是返回值不同时 函数重载也不能解决
3)有多米诺效应,一个方法出错其它的也都会出错,不便于维护
使用公共基类,将通用的方法放在公共基类中
缺点:
1)借助公共基类来编写代码,将失去类型检查的优点
2)以后实现的许多类,都必须继承自这个特定的类,代码维护较为困难
使用特殊的预处理程序
缺点:他不是函数,不能进行参数检测,安全性较低,也不便于代码调试
因此基于以上这些方法的缺点C++wei我们引出泛型编程的概念
泛型编程:编写类型无关的逻辑代码,时代码复用的一种手段。而模版时泛型编程的基础模版又可分为函数模版和类模版
二 模板函数&模板形参&函数重载
(一)函数模版: 代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的
特定类型版本
1 函数模版的格式:
template
其实函数调用如下图所示
第三种传参是错误的,函数无法由实参来推演模版形参类型
最后两种均发生了类型转换,调用机制和第二种相同
注意: 模板被编译了两次:
- 实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号
- 在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用
3 实参推演: 从函数实参确定模板形参类型和值的过程称为模板实参推断多个类型形参的实参必须完全匹配
4 类型形参转换
一般不会转换实参以匹配已有的实例化,相反会产生新的实例。
编译器只会执行两种转换:
1)const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用
2)数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指 针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。
(二)模板参数
1 模版参数分为类型参数和非类型形参数
2 使用模版参数是要注意:
模板形参名字只能在模板形参之后到模板声明或定义的末尾之间使用,遵循名字屏蔽规则
模板形参的名字在同一模板形参列表中只能使用一次
所有模板形参前面必须加上class或者typename关键字修饰
在函数模板的内部不能指定缺省的模板实参
3 非类型模版参数: 非模板类型形参是模板内部定义的常量,在需要常量表达式的时候,可以使用非模板类型参数。
例如在求数组长度时候的
template
注意:函数的所有重载版本的声明都应该位于该函数被调用位置之前。
【说明】
1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例
化为这个非模板函数。
例如上述 Max(10, 20, 30)的调用机制如下图 即 T Max变为 int Max
2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,
那么将选择模板。
例如上述Max(10, 20)的调用机制,他并没有用模版实例化出函数
3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,
而且所有的模板参数都应该根据实参演绎出来。
例如Max<>(10, 20)他并不能调用已给出的int max,而是用模板实例化出了一个新的函数
4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
因此并不能这样调用Max(10.0,20)
未完待续ing。。。。
首先来看一段实现加法函数的代码
int Add(const int &_iLeft, const int &_iRight) { return (_iLeft + _iRight); }
这个函数现在只能接收int类型的数据,如果我们想让他成为通用的加法函数该怎么办呢?
根据我们在C++前一段时间所学的知识,有三种方法来解决这个问题,但是这些方法也有 各自不同的问题
函数重载
缺点:
1)代码复用率太低,只要有新类型出现就要再写一个像对应的函数,而这些函数的 函数体都相同
2)如果函数只是返回值不同时 函数重载也不能解决
3)有多米诺效应,一个方法出错其它的也都会出错,不便于维护
使用公共基类,将通用的方法放在公共基类中
缺点:
1)借助公共基类来编写代码,将失去类型检查的优点
2)以后实现的许多类,都必须继承自这个特定的类,代码维护较为困难
使用特殊的预处理程序
缺点:他不是函数,不能进行参数检测,安全性较低,也不便于代码调试
因此基于以上这些方法的缺点C++wei我们引出泛型编程的概念
泛型编程:编写类型无关的逻辑代码,时代码复用的一种手段。而模版时泛型编程的基础模版又可分为函数模版和类模版
二 模板函数&模板形参&函数重载
(一)函数模版: 代表了一个函数家族,该函数与类型无关,在使用时被参数化,根据实参类型产生函数的
特定类型版本
1 函数模版的格式:
template
template <typename T> T Add(Tl,Tr) { return r + l; } int main() { cout << Add(1, 2) << endl; cout << Add(1.2, 2.3) << endl; cout << Add(1, 2.4) << Lendl;/这是错误的/ cout << Add<int>(1, 2.4) << endl; cout << Add(1, (int)1.2)<<endl; }
其实函数调用如下图所示
第三种传参是错误的,函数无法由实参来推演模版形参类型
最后两种均发生了类型转换,调用机制和第二种相同
注意: 模板被编译了两次:
- 实例化之前,检查模板代码本身,查看是否出现语法错误,如:遗漏分号
- 在实例化期间,检查模板代码,查看是否所有的调用都有效,如:实例化类型不支持某些函数调用
3 实参推演: 从函数实参确定模板形参类型和值的过程称为模板实参推断多个类型形参的实参必须完全匹配
4 类型形参转换
一般不会转换实参以匹配已有的实例化,相反会产生新的实例。
编译器只会执行两种转换:
1)const转换:接收const引用或者const指针的函数可以分别用非const对象的引用或者指针来调用
2)数组或函数到指针的转换:如果模板形参不是引用类型,则对数组或函数类型的实参应用常规指 针转换。数组实参将当做指向其第一个元素的指针,函数实参当做指向函数类型的指针。
(二)模板参数
1 模版参数分为类型参数和非类型形参数
2 使用模版参数是要注意:
模板形参名字只能在模板形参之后到模板声明或定义的末尾之间使用,遵循名字屏蔽规则
模板形参的名字在同一模板形参列表中只能使用一次
所有模板形参前面必须加上class或者typename关键字修饰
在函数模板的内部不能指定缺省的模板实参
3 非类型模版参数: 非模板类型形参是模板内部定义的常量,在需要常量表达式的时候,可以使用非模板类型参数。
例如在求数组长度时候的
template
int Max(const int& left, const int & right) { return left>right? left:right; } template<typename T> T Max(const T& left, const T& right) { return left>right? left:right; } template<typename T> T Max(const T& a, const T& b, const T& c) { return Max(Max(a, b), c); }; int main() { Max(10, 20, 30); Max<>(10, 20); Max(10, 20); //Max(10, 20.12); Max<int>(10.0, 20.0); Max(10.0, 20.0); return 0; }
注意:函数的所有重载版本的声明都应该位于该函数被调用位置之前。
【说明】
1、一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例
化为这个非模板函数。
例如上述 Max(10, 20, 30)的调用机制如下图 即 T Max变为 int Max
2、对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调动非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,
那么将选择模板。
例如上述Max(10, 20)的调用机制,他并没有用模版实例化出函数
3、显式指定一个空的模板实参列表,该语法告诉编译器只有模板才能来匹配这个调用,
而且所有的模板参数都应该根据实参演绎出来。
例如Max<>(10, 20)他并不能调用已给出的int max,而是用模板实例化出了一个新的函数
4、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
因此并不能这样调用Max(10.0,20)
未完待续ing。。。。
相关文章推荐
- PAT-B 1052. 卖个萌
- 【leetCode】House Robber python实现
- AOP编程简介及其在Spring框架中的使用
- c++面试题
- 手把手教你整合最优雅SSM框架:SpringMVC + Spring + MyBatis
- python 统计单词个数---不去重
- python并发编程greenlet模块学习
- 开山篇
- 【leetCode】Binary Tree Level Order Traversal python实现
- JAVA、OC的内存管理机制的本质
- C#最短路径算法demo
- JAVA集合框架Collection
- 28. Implement strStr() [easy] (Python)
- [Java] 继承中,父类被覆盖的成员变量、方法的可访问性
- 【leetCode】Binary Tree Zigzag Level Order Traversal python实现
- Vagrant和VirtualBox搭建基于windows的Ruby on Rails基本开发环境(共享文件夹配置)
- C002-CPP-用malloc()存储任意长度的键入字符串
- QT笔记之VS2010 Qt中导入qrc资源文件
- delphi 编译生成ipa文件
- 看开源代码如何解析ELF文件