CSDN博客

img Jinhao

混沌 IN C++::Generic Programming

发表于2008/10/3 14:29:00  1338人阅读

难度:
 

现代程序开发最关注的一件事之一就是如何提高代码的可复用性和可维护性。

OOP
提供了抽象概念来构建一个统一的世界模型,具像的物理对象被实现在这个简单的抽象模型体系中,最终形成庞大的树型结构来覆盖由该抽象涉及到的方方面面,可复用性由此诞生。

GP
提供了另类的复用方法,让算法与类型无关。

在大多数的开发中,GP的运用几乎为空白,其实这并不是坏现象,除了让部分代码变得稍微优雅,剩下的可以说在大部分情况下,GP都是画蛇添足。在开发中, 我们努力用OO的知识和经验来创建类,让这些类对象相互协同工作来达到目的,一般情况下,我们是处在一个很小的问题域中着手解决具体的问题,不需要更多的 思考,所以template关键字几乎可以不用出现在我们编写的代码当中。

在以往的观点中,GPOOP就像两条平行线,一边是静态多态,一边是动态多态,这样的观点让很多人误解了GP,加上在实际工作中,几乎不写template关键字,从而加深了这种误解。

到底GP存在的意义在哪里?相信大多数C++程序员都会用到STL,正是GP造就了STL的应用如此广泛。GP是一种用来开发高效,高复用程序库的编程范式,所以在实际工作的大多数项目中,GP对我们来说可有可无。用GP来分析问题的三个步骤:
1
,将抽象问题域分类成Concepts.
STL中,迭代器按行为被分类成5类。Input/Output/Forward/Bidirectional/Random Access Iterator

2
,基于这些Concepts,设计泛型算法。
例如std::generate要求Forward Iterator,而std::next_perutation要求Bidirectional Iterator.

3,
创建Concepts的具体模型。
例如,std::vectorIteratorstd::mapIterator

其实GP的分析方式与OOP极其类似,都是由具体的事物寻找抽象,然后按抽象来设计,最后基于抽象实现具象。

GP编写的泛型程序库到底好在哪里?
可复用性:
我们尝试用OO来实现vector

  1. class oo_vector
  2. {
  3. public:
  4.     void push_back(vec_elem_t& r)
  5.     {
  6.         vec_elem_t * n = r.clone(*this);
  7.         //hold n ...
  8.     }
  9. };

如果我们要使用oo_vector,那么存储的元素类型必须由vec_elem_t派生并实现clone方法。如果用C++ Templates来实现,复杂度自然降低。至少我们的元素类型不会出现派生自vec_elem_t, map_elem_t, list_elem_t等等这种庞大的多重继承的情况。

粘和性:
用上面的oo_vector来思考。如果有一个现成的类,要让oo_vector来操作,该怎么办?C++ Templates应用到这种情况下大大提高了粘和性和可复用性。

Templates
C++变得太了?
C++
是强类型语言,继承确定了两个类的关系,这种关系可以某些方法作用于子类对象上,他们之间存在着一种限制。而对于一个泛型算法,它能接纳的模板参数 T,从形式上,看不到任何限制,但这也许会使你的代码编译失败。例如把std::listiterator传递到std::find中,得到的编译错误是 iterator缺少某某东西,在这种情况下,如果编译错误能提示listiterator不能用在find里,这样就会友好很多。其实这不仅仅只是提示得友好,因为我们在设计这种泛型算法的时候就是依据上面提到的Concepts,这种 Concepts在目前的C++语言中,只是一个潜在限制,作为泛型库的使用者,很容易忽略掉这种限制。或许有人会认为,如果C++引入Concepts 的限制来做类型的检查,那么它还会是GP吗?它仍然是GP,显而易见的,泛型库的设计是从Concepts出发,这好比一个子类是从基类出发一样。

Concepts
会是画蛇添足吗?
就算语言引入了Concepts,那么listiterator仍然不能用到find中去,这和没有Concepts的情况完全一样。Concepts 描述了一组抽象的行为,我们可以提供一个算法函数来处理具有这种行为的类型,它的引入会把人们的关注目光从围绕T上转移到Concept上,这能更好地表达每个抽象的核心思想。按Concepts来特化算法,比按类型来特化算法是更好GP,因为GP原本就与类型无关。在解决list::iterator应用到find的问题上,只需要特化一个符合list::iterator Conceptfind即可。

现在看来GPOOP似乎很相似了,从分析的角度来说,他们的方向是一样,只是方法不同。这两个范式的区别不像OOP和面向过程那样,立竿见影。或许说,GPOOP都应该是一种泛型GP是基于行为概念的抽象,OOP则是基于事物概念的抽象。在OO的设计中,我们仍然会考虑到行为这一问题,只不过从OO的角度来说,这太隐晦,而GP在这方面则表达得更好,更抽象。

0 0

相关博文

我的热门文章

img
取 消
img