Chinaunix首页 | 论坛 | 博客
  • 博客访问: 614454
  • 博文数量: 79
  • 博客积分: 848
  • 博客等级: 军士长
  • 技术积分: 1800
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-26 19:30
文章分类

全部博文(79)

文章存档

2015年(4)

2013年(39)

2012年(36)

分类: C/C++

2013-06-17 15:42:02

支持泛型编程是c++非常强大的一个特性,我们可以通过定义一个模板函数和模板类,大大精简我们的代码,极大的增强程序的复用性和鲁棒性。之前本人一直对于泛型编程这部分了解的比较少,今天重新温习了一下,所以通过这篇博文来记录一下自己的一点心得。
首先我们还是以一个例子来开始,我定义了一个如下的函数模板用来实现,两个对象的比较功能:

点击(此处)折叠或打开

  1. template<typename T> int compare(const T &first, const T &second)
  2. {
  3.     return first > second ? first : second;
  4. }
上述模板非常的简单,就是用来返回两个对象中数值较大的对象的副本。在通常的情况下,这个模板工作上是不存在任何问题的,但是如果我们想要比较两个字符串的大小的时候,这个模板的工作,并不能让我们感到满意,因为我们在模板的形参中传递的是两个对象的引用,假如我们传递两个字符串指针的实参,其实模板中实现的仅仅是对于两个指针实参指向的地址的比较,而并不是指针所指向的内容的比较,我们如何去解决这样的一个问题呢,首先我们想到的是可以使用模板的特化,重新定义一个模板的特化版本来处理两个字符串的比较,于是就有了下面的模板特化:

点击(此处)折叠或打开

  1. template<> //全特化的表示方法
  2. int compare(const char* const &first, const char* const &second)
  3. {
  4.     return (strcmp(first, second) >= 0) ? first : second ;
  5. }
上面的书写方式,是模板特化时候标准的书写形式,在本例中我们实现了一个基于字符串比较的功能,并且返回了两者中较大值。但是假如我们子书写特化版本的时候,忘记了template<>标志,书写成如下的形式:

点击(此处)折叠或打开

  1. int compare<const char*>(const char* const &first, const char* const &second)
  2. {
  3.     return (strcmp(first, second) >= 0) ? first : second ;
  4. }
结果会如何呢?这个时候编译器会告诉我们:

点击(此处)折叠或打开

  1. 错误: 特例化成员‘::compare<const char*>’需要‘template<>’语法
假如我们忘记了compare后面尖括号的中类型的书写,或者更有甚者我们把两者都忘记了会出现什么情况呢:

点击(此处)折叠或打开

  1. int compare(const char* const &first, const char* const &second)
  2. {
  3.     return strcmp(first, second);
  4. }

  5. template<>
  6. int compare(const char* const &first, const char* const &second)
  7. {
  8.     return strcmp(first, second);
  9. }
这种情况下,编译器是否还会提示我们吗?经过编译发现,当上述两种情况同时存在的时候编译器编译通过。这个是什么原因呢?
我这个时候实际测试了一下,这两个函数,为了加以区别我们修改了一下第一个函数中实现我们改成下面:

点击(此处)折叠或打开

  1. int compare<const char*>(const char* const &first, const char* const &second)
  2. {
  3.     return 0 - strcmp(first, second);
  4. }
我们让第一个函数返回结果的相反数,然后我们来调用这个函数,如下:

点击(此处)折叠或打开

  1. int main()
  2. {

  3.     int a = 10;
  4.     int b = 2;
  5.     const char *p1 = "dang";
  6.     const char *p2 = "dao";
  7.     cout << "resulst strcmp: " << compare(p1, p2) << endl;
  8.     cout << "result int: " << compare(a, b) << endl;
  9.     return 0;
  10. }
大家可以想象一下,执行的结果:

点击(此处)折叠或打开

  1. resulst strcmp: 1
  2. result int: 10
这说明了什么呢,说明在字符串比较的时候,调用了我们定义的修改之后的函数实现,而忽略了我们实现的漏掉了compare后面的尖括号中类型定义的特化版本,但是漏掉类型的定义并不是这里关键,即便我们把漏掉的尖括号加上,结果还是一样的。

原因到底什么呢?

是这样的,在c++之中,是允许用户重载一个函数的,所谓函数的重载,就是我们可以用同一个函数名,通过改变传入该函数的实参,来定义不同的函数实现。更为强大的一点是,c++也允许我们重载一个函数模板!!

c++中确定函数调用的步骤如下:
(1)为这个函数名建立一个候选函数的集合,包括:
a、与被调用函数重名的任意普通的函数。
b、任意函数模板的实例化,通过模板实参的推断匹配
(2)首先是查找哪些普通函数是可行的(确定这个普通函数是否可行,必须是传入实参和函数形参类型的精确匹配,经过类型转换匹配的不符合要求),然后才是查找模板中的实例来匹配。

所以我们会发现,在本例中我们陋写完成的函数特化,实际上是对于模板函数的重载,重载函数会优先于模板在函数调用时进行匹配,无论是原来的模板还是我们特化之后的模板,他们优先级都是要低于我们重载的函数,当然重载函数匹配需要形参和传入实参的完全匹配。












阅读(3128) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~