为什么需要模板
比如需要设计一个描述点的类,大致很快可以写成这样:
classPoint_F
{
public:
/*默认传入参数为0,0*/
Point_F(floatx0=0,floaty0=0)
:x(x0),y(y0)/*初始化列表*/
{}
/*用const修饰函数,表示函数不会修改成员数据*/
floatget_x()const{returnx;}
floatget_y()const{returny;}
private:
/*一般会将数据放在私有区,以对外隐藏*/
floatx;
floaty;
};
可问题是,在有的场合这点的坐标系有可能不需要浮点,比如界面设计中点往往是整型表示即可,那此时就需要再设计一个整型成员类:
classPoint_I
{
public:
/*默认传入参数为0,0*/
Point_f(intx0=0,inty0=0)
:x(x0),y(y0)/*初始化列表*/
{}
/*用const修饰函数,表示函数不会修改成员数据*/
intget_x()const{returnx;}
intget_y()const{returny;}
private:
/*一般会将数据放在私有区,以对外隐藏*/
intx;
inty;
};
可是在应用代码中,往往发现对于不同数据成员的应用操作确实基本类似,而且应用代码往往这两种(甚至更多成员数据类型)都可能会同时用到,仅仅因为数据类型就需要笨笨的将原代码在改写一下,在现代高级语言中,这显然就比较机械了。
C++中有没有可能将不同成员数据类型但是其顶层逻辑相同的对象,设计为一个类呢?就比如:
C++模板编程正是为了解决这样的需求而设计的机制。该机制允许函数或类使用泛型类型(generic type)进行操作。从而,函数或类就可以处理许多不同的数据类型,而无需为每种数据类型重写相应的类或者函数。
怎么实现的呢?
这里又可以大致分这样三种情况:
函数模板
函数模板其基本语法范式为:
template<classidentifier>function_declaration;
template<typenameidentifier>function_declaration;
- template 为模板关键字
- 、 定义函数参数泛型类型或函数体类变量泛型类型
比如:
#include
usingnamespacestd;
template<typenameT>
Tmax(Ta,Tb)
{
returna>b?a:b;
}
又或者写成如下形式:
#include
usingnamespacestd;
template<classT>
Tmax(Ta,Tb)
{
returna>b?a:b;
}
那么或许有的朋友会任务关键字class就意味着自定义类,而typename则是基本数据类型,比如int,float等,这样理解其实是不对的,从C++编译器的角度template 与template 其语义是一样的,都是泛型,用户在使用这个模板函数的时候,所传入的参数都既可以是基本数据类型,也可以是类名。
对于上面的代码,或许初使用的朋友还会问,是不是可以随便传入类,这有可能编译不过。为什么呢?你传入的类需要支持>操作符,如果对于某个类你想使用该函数,而本身不支持>操作符,则需要实现>操作符。
类模板
与函数模板类似,类内部成员数据或者函数的参数或变量会使用,模板关键字定义的泛型名。比如:
template<typenameT>
classPoint_T
{
public:
Point_T(Tx0=0,Ty0=0)
:x(x0),y(y0)
{}
Tget_x()const{returnx;}
Tget_y()const{returny;}
private:
Tx;
Ty;
};
这小段代码就回答了之前提出的问题,可以支持不同数据类型的点。
intmain()
{
Point_T<int>p1(1,2);
Point_T<float>p2(1.1f,2.2f);
cout<< p1.get_x() << endl<< p1.get_y() << endl;
cout<< p2.get_x() << endl<< p2.get_y() << endl;
}
以上述简单例子看,分别构造了整型点p1,以及浮点型点p2,那么究竟怎么做到的呢?为了理解得更清楚,这里将其关键汇编代码段拷贝下来简要看看:
Point_T p1(1, 2);
000C1D6C push 2
000C1D6E push 1
000C1D70 lea ecx,[p1]
000C1D73 call Point_T::Point_T (0C11D1h)
Point_T p2(1.1f, 2.2f);
000C1D78 push ecx
000C1D79 movss xmm0,dword ptr [__real@400ccccd (0C7B34h)]
000C1D81 movss dword ptr [esp],xmm0
000C1D86 push ecx
000C1D87 movss xmm0,dword ptr [__real@3f8ccccd (0C7B30h)]
000C1D8F movss dword ptr [esp],xmm0
000C1D94 lea ecx,[p2]
000C1D97 call Point_T::Point_T (0C1064h)
可见编译器对不同类型参数实际上做了相应解析,相当于根据用户程序传入的参数编译出相应的多份代码。所以可以简单理解成编译器根据不同泛型实际参数类型生成了相应的处理代码。而前面所说的模板函数其原理也基本类似。
总结一下
通过些简单例子,梳理一下模板函数以及模板类的基本概念以及原理,理解了这两个概念,就比较容易理解成员模板。所谓泛型模板编程,其本质是编译器针对不同参数类型解析解析生成相应的处理代码。学会使用模板泛型编程你会发现你会少写很多代码,代码看起来会比较优雅,而其实操作起来也没有想象中那么难。
原文标题:什么是函数模板、类模板?怎么做到的?
文章出处:【微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。
-
编程
+关注
关注
88文章
3587浏览量
93577 -
函数
+关注
关注
3文章
4303浏览量
62409 -
原理
+关注
关注
4文章
550浏览量
44865
原文标题:什么是函数模板、类模板?怎么做到的?
文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论