模板与泛型编程的基础
2016-09-06 18:04
239 查看
1、前言
模板可以让我们以独立任何具体类型的方式编写代码,我们只需要在运行的时候给定具体的类型就可以。而泛型编程可以让我们用同样的方式操作不同的数据对象,比如vector迭代器这些就是很好的例子。模板是泛型编程的基础,因此,了解这模板和泛型编程有助于我们写出适用范围更广的代码。2、模板的定义
模板的定义分为两种,一种是函数的模板定义,一种是类的模板定义。下面分别讲解。2.1 函数的模板定义
为了避免出现不同参数类型使用相同函数体而导致多重定义的情况,写一个函数模板是很好的解决方案。比如有如下两个函数:int conpare(const int &a,const int &b) { if(a<b) return 0; if(b<a) return 1; return -1; } int compare(const string &a,const string &b) { if(a<b) return 0; if(b<a) return 1; return -1; }
我们可以发现,除了形参类型不同之外,函数体是一模一样的。为了不重复这样写,可以定义一个模板函数:
template<typename T> int compare(const T &a,const T &b) { if(a<b) return 0; if(b<a) return 1; return -1; }
用关键字template声明一个模板类型,后面接着的是模板形参表,如果有多个模板形参,用逗号分隔。使用模板函数和正常函数一样。
int a=1,b=2; string c="aa",d="dd"; compare(&a,&b); compare(&c,&d);
如上,可以发现使用模板函数和正常函数是没有区别的。
如果需要将模板函数定义为内联函数,那么inline修饰符必须在模板形参表之后,函数名之前。比如:
template<typename T> inline int compare(T &a,T &b) { //...... }
2.2 类模板的定义
除了定义函数模板外,也可以定义类模板。如下:template <typename T> class Stack { public : Stack(); ~Stack(); Stack(const T &stack){}; T top(); private : //...... }
同样的也会iyogtemplate开头,后接一个模板形参表,多个形参用逗号分隔,形参在整个类中都可以使用。使用类模板可以如下:
Stack<int> s1; Stack<double> s2; Stack<string> s3; int top1=s1.top(); double top2=s2.top(); string top3=s3.top();
可以发现除了定义对象之外,其它的调用和正常的类是没有区别的。
2.3 模板形参
现在讲解模板形参的声明以及作用域。假设有如下模板函数:typedef int T; template<class T> T compare(const T &a,const T &b) { T c; if(a<b) c=b; if(b<a) c=a; }
在这里我们声明了一个int的别名T以及声明了一个模板函数,模板形参为T。和局部变量一样,模板形成名称会覆盖全局名称,因此c是一个不确定的类型,并不一定是int型。所以如果模板形参含有多个形参值,值的名字必须不相同。如果希望声明一个模板函数,可以如下:
template<class c> c compare(const c &a,const c&b); template<class d> d compare(const d &a,const d&b);
上面两种都是声明compare的正确形式,也就是说,声明和定义的模板形参名字不必相同。
2.4 typename和class的区别
本质上来说,typename和class是一样的,都是声明后面的标识为类型名。但是typename是作为标准C++加入c++中的,因此在旧的程序是不能使用typename的。在一个模板中,typename和class是可以一起使用的。比如:template<class T,typename V> int set(const T ¶m1,const V ¶m2) { }
2.5 非类型形参
模板形参分为类型形参和非类型形参。非类型形参一般指的是值。比如:template <typename T,size_t N> void set(T (¶m) ) { }
其中N是非类型形参,它的值是可以在运行的时候再确定的。比如:
int a[100]; double b[100]; set(a); set(b);
这样就可以引用模板数组了。
3、模板函数实例化
模板函数本身的类型是不确定的,编译器在根据特定类型产生模板的过程叫做实例化。实例化后的模板是一个确定的类型,类模板在引用实际模板类类型时实例化,函数模板在被调用的时候实例化。3.1、类模板实例化
前面提到的Queue就是一个类模板,使用它时必须声明类模板的参数类型。比如:Queue<string> q;
string会替代每次类型形参的出现。而如果我们不指定特定类型去实例化模板的话,是会报错的。比如:
Queue q
因此类模板形参是必须的。
3.2、函数模板实例化
函数模板实例化过程,是可以根据实参的类型进行自动转换的,但是两个实参的类型必须相同或者可以进行显示转换,因为函数模板实例化过程中会涉及到一个匹配的问题,只有匹配成功了,才可以进行调用。比如:int a; string b; compare(a,b);
上述的compare函数模板会实例化失败。
相关文章推荐
- c++模板与泛型编程基础
- c++模板与泛型编程基础
- c++模板与泛型编程基础
- c++模板与泛型编程基础
- C++模板与泛型编程基础
- c++基础——模板和泛型编程
- c++模板与泛型编程基础
- C++模板与泛型编程基础
- c++模板与泛型编程基础
- c++模板与泛型编程基础
- C++语法基础--模板与泛型编程--函数模板,类模板,模板形参,非模板形参
- c++模板 与 泛型编程基础
- c++模板与泛型编程基础
- 【C++】泛型编程基础:模板通识
- 图像处理:基础(模板、卷积运算)
- 模板与泛型编程 -part1
- Java的模板引擎Velocity初体验-Java基础-Java-编程开发
- 图像处理:基础(模板、卷积运算)
- 第16章 模板与泛型编程
- CodeSmith使用基础教程 一 — 模板