【C++】函数模板
来源:互联网 发布:美工捅死策划 编辑:程序博客网 时间:2024/04/28 07:55
函数模板
所谓模板,是C++中实现多态的又一方法。我们已经知道函数重载可以实现多态,让一个函数名多用。这样可以简化函数的调用形式,但是又必须定义每一个函数。
C++提供模板正是为了简化这一个过程。
探索函数重载的缺点
首先,让 我们写一个Add函数
int Add(int x,int y){return x - y;}
ok,现在我们要对Add函数进行重载
char Add(char x, char y){return x - y;}
我们新定义了一个日期类型Date,我们又得对Date进行重载
Date Add(Date& d1, Date &d2){return d1 - d2;}
额,我们为什么如此的粗心。。。把“+”写成了“-”
这样的话,我们需要修改所有重载函数的逻辑。这就是函数重载的缺点。
虽然只需要把所有的加号换过来就好了,可是由于我们写的是非常简单的函数(只有一条返回语句)。当我们写了很长很长的语句时,这就会有很大的工作量了
函数重载的缺点:
(1)每当需要新的类型出现后,需要重载对应添加的函数
(2)函数重载的各个函数,大体函数逻辑一样,只是改变了类型。导致代码的利用率不高。
(3)当逻辑出现问题时,需要修改所有重载的函数。不方便维护
(4)函数重载无法解决返回值的问题
泛型编程
由于函数重载的诸多缺点,我们引入了【泛型编程】的概念。所谓的【泛型编程】,就是编写与类型无关的代码,是提高代码复用的一种手段。
而泛型编程,又包括【函数模板】和【类模板】。模板是泛型编程的基础!
函数模板
关键字 template
函数模板定义格式:
template<typename T>T Add(T x,T y){return x + y;}
注意:
(1)函数模板不是类或者函数,它只是一个蓝图。只有在模板实例化后编译器才会为之生成对应的类或者函数。
(2)模板会被编译两次,第一次检查模板里的语法是否有错,如缺少分号;第二次则是在实例化的时候,会查看所有的调用是否都是有效的。
参数转换
编译器只能执行两种转换
1、const转换
接收const对象指针或者const对象引用的参数,可以用非const对象的指针或引用进行调用
template<typename T>T Add(const T& x,const T& y){return x + y;}int main(){int a = 10;int b = 20;int &ra = a;int &rb = b;cout << "a + b =" << Add(ra, rb) << endl;system("pause");return 0;}2、函数或者数组到指针的转换
如果模板不是引用类型的话,那么它对函数或者数组类型的实参应转为指针
template <typename T>T Add(const T* x, const T* y){return (*x + *y);}int main(){int a[5] = {0};int b[5] = {1,2,3,4,5};cout << "a + b = " << Add(a, b) << endl;return 0;}
模板参数
包括两种类型,分别是类型形参和非类型形参
模板形参的名字只能在模板形参之后,到模板的声明和定义的结束使用,遵循就近原则。
template<typename T>//FunTest函数模板void FunTest(T t){cout << "t's type:"typeid(t).name() << endl;cout << "global's type:"typeid(global).name() << endl;}T global;int main(){FunTest<int>(5);return 0;}
注意:
1、模板形参的名字在同一模板参数列表内只能使用一次
template<typename T,typename T>void FunTest(T a,T b){return;}
2、所有模板前必须加上class或者typename关键字进行修饰
template<typename T,U>void FunTest(T a,U b){return;}
函数模板的重载
1、函数模板和函数模板进行重载
当然,函数模板也是可以重载的。
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(){cout << Max(1, 2) << endl;cout << Max(1.2, 3.4, 5.6) << endl;system("pause");return 0;}上面我们重载了两个求最大值的函数模板,他们只有模板的参数不同而已
2、函数模板和非模板的函数进行重载
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(){cout << Max(10, 20, 30) << endl;cout << Max<>(10, 20) << endl;cout << Max(10, 20) << endl;cout << Max(10, 20.12) << endl;cout << Max<int>(10.0, 20.0) << endl;cout << Max(10.0, 20.0) << endl;system("pause");return 0;}注意:在此种情况下,编译器会先在非模板的函数中搜寻与之参数类型,个数完全匹配的函数;如果找到了,编译器便会调用它,不会让函数模板进行实例化;
如果没有找到,则通过函数模板进行实例化;如果想让编译器不调用非模板函数,则需要在调用的时候进行显示实例化,这样的话,函数模板实例化生成的代码也和原来定义的
非模板函数不是同一块代码
模板函数的特化
有时候,不能写出对所有可能实例化出来的类型都最适合的模板,在某些情况下,通过模板定义的函数有可能对于某个类型是错误的,或者编译失败,或逻辑错误
template <typename T> int Compare(T s1, T s2) { if(s1<s2) return -1; else if(s1>s2) return 1; else return 0; } int main() { char* str1 = "abcd"; char* str2 = "ghf"; cout<<Compare(str1,str2)<<endl; system("pause"); return 0; }如果这样写我们的代码,那么,你就会发现比较的结果一直是不变的
对此,我们只需要特化一下~
template<>int Compare<const char*>(const char* str1,const char *str2){return strcmp(str1, str2);}就可以避免错误的发生
注意:特化一定要和原模板函数版本的形参类型完全一致
- 【c/c++】函数模板和模板函数
- C/C++ 函数模板
- c++:函数模板
- 【C++】函数模板
- 【c++】函数模板
- C语言函数模板
- C++:函数模板
- 【C++】模板函数总结!!!
- C/C++:函数模板与类模板
- [C/C++]模板函数与模板类
- 学习C++模板---模板函数
- Linux C/C++ 模板:函数模板
- C++,template,类模板和函数模板
- C++:函数模板、类模板及其特化
- C++---函数模板与类模板
- C++_函数模板基础知识
- C语言实现函数模板
- C++_函数模板基础知识
- 机器视觉之图像add的三种方式
- C语言中的一些关键字(五)
- openssl-devel和openssl 是什么具体关系
- 关于静态页面和动态页面的解释
- 一道防AK的好题【数列】
- 【C++】函数模板
- 【C语言】熟悉预处理标识符和宏
- ANDROID STUDIO安装
- codeforces733C Epidemic in Monstropolis
- iOS集成环信SDK(二)——集成环信SDK后,项目名称变了
- XML约束
- 我们为什么要学习JAVA?
- AngularJS 最常用的八种功能
- error C2146: 语法错误: 缺少“;”(在标识符“m_tTimer”的前面) error C4430: 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int