`
shi5jin
  • 浏览: 37186 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
社区版块
存档分类
最新评论

站在巨人肩上的思考[连载] (4)

阅读更多
首先感谢  spinach 的鼓励支持。你给了我很大的动力,真诚的希望我的文字能够对你有所帮助。 
这篇之后可能周末前不会再更新了,因为手头上有个项目需要集中精力先搞定。
本笔记首发www.iteye.com 转载请您注明出处。谢谢。
                                                                                                        -- Gavin

//-----------------------------------------------------------------------------------------------

Tips: Java并非平台无关,它本身就是平台。
          "Java is not platform-independent, it is the platform." -- Bjarne Stroustrup (B.S)

第二章 C++概览

       这一节很短,stroustrup给我们明确界定了C++的边界以及组成部分:

      <v:shapetype id="_x0000_t186" filled="f" path="m@9,nfqx@0@0l@0@7qy0@4@0@8l@0@6qy@9,21600em@10,nfqx@5@0l@5@7qy21600@4@5@8l@5@6qy@10,21600em@9,nsqx@0@0l@0@7qy0@4@0@8l@0@6qy@9,21600l@10,21600qx@5@6l@5@8qy21600@4@5@7l@5@0qy@10,xe" adj="1800" o:spt="186" coordsize="21600,21600"><v:formulas><v:f eqn="val #0"></v:f><v:f eqn="val width"></v:f><v:f eqn="val height"></v:f><v:f eqn="prod width 1 2"></v:f><v:f eqn="prod height 1 2"></v:f><v:f eqn="sum width 0 #0"></v:f><v:f eqn="sum height 0 #0"></v:f><v:f eqn="sum @4 0 #0"></v:f><v:f eqn="sum @4 #0 0"></v:f><v:f eqn="prod #0 2 1"></v:f><v:f eqn="sum width 0 @9"></v:f><v:f eqn="prod #0 9598 32768"></v:f><v:f eqn="sum height 0 @11"></v:f><v:f eqn="sum @11 #0 0"></v:f><v:f eqn="sum width 0 @13"></v:f></v:formulas><v:path textboxrect="@13,@11,@14,@12" o:connectlocs="@3,0;0,@4;@3,@2;@1,@4" o:connecttype="custom" limo="10800,10800" o:extrusionok="f"></v:path><v:handles><v:h position="topLeft,#0" yrange="0,5400" switch=""></v:h></v:handles></v:shapetype><v:shape id="_x0000_s1026" style="WIDTH: 94.6pt; HEIGHT: 74.9pt; rotation: 180; mso-position-horizontal-relative: char; mso-position-vertical-relative: line" type="#_x0000_t186" filled="t" adj="1305" strokeweight="1.25pt" strokecolor="#82acd0" o:allowincell="f"><v:shadow opacity=".5"></v:shadow><v:textbox style="mso-next-textbox: #_x0000_s1026" inset="21.6pt,,21.6pt">

  • 更好的C
  • 数据抽象
  • 面向对象
  • 泛型设计<o:p></o:p>
</v:textbox><w:wrap type="none" anchory="margin" anchorx="margin"></w:wrap><w:anchorlock></w:anchorlock></v:shape>

       曾经在C++primer中也听说过这种分法,这次由C++之父再次确认,分量不一般。个人觉得这四层是自上向下逐级抽象的。

C是基础。是程序最基本的表达形式,个人认为也是确实完成设计目标的载体。C重视过程,强调算法,讲究高效,长于函数,特别适合开发底层的、对执行效率以及响应时间要求苛刻的程序,这些是他的优点。同时他也有他的缺点,例如类型不安全,程序员可以通过强制类型转换在内置类型之间“跳来跳去”。还有就是令人眼花缭乱的指针以及基本依赖于程序员记忆力的内存管理、边界检查。以上几点C语言与生俱来的瑕疵给程序员带来无数痛苦的回忆。一个编译通过的程序,我们经常在运行时得到令人摸不着边际的结果。C++在此基础之上做出了略微的改善,诸如更多的类型检查,更“智能”的内存管理等等。但是这并不能从根本上解决C的问题。另外,在开发效率上也比较令人头疼。C语言的代码规模近似的与问题的规模成n2速度增长。在这种情况下,虽然编写、维护1000行左右的代码时,我们几乎体会不到CC++的明显区别,甚至会觉得C更简洁、明了。但是当我们的程序膨胀到几千、几万或几十万行的规模的时候,我们会发觉身心俱疲——在这样的程序中找到类似指针指向错误、内存访问越界、内存泄露的bug,并不比在上海找一只去过杭州的“小强”更容易。所以我想摆在B.S.面前的首要任务就是解决C中数据繁杂凌乱的局面?怎么办?对,就像你想象中的那样,进行数据抽象。其实这个问题在C时代就有许多优秀的程序员进行过艰苦卓绝的斗争。最有名的一种解决方案就是把相关的数据都“打包”到一个struct当中,然后编写出许多以该struct为前(后)缀的函数用以对他们进行操作。比如说create_xxx(), destroy_xxx(), do_something_xxx();这些都被我们当作经典模式而奉行。

C++首先就是对这种解决方案进行抽象、提取、完善。引入class关键字,引入publicprotectprivate等描述字,赋予他们完整的语义,从而在语言本身的这个角度,对“基于对象”(Object-Based,当然这是之后提出的概念)编程进行了实质的支持,而不再是利用C的语法进行的一种“近似模拟”。现在我们可以把相关的数据、以及操作单独得组织到一个自定义的类型当中,不仅可以节省了名字空间,简化了操作,而且更重要的是使“写人类比较容易理解的代码”不再是Impossible Mission,还有最后也是最重要的一点,提供了接口与实现分离的语言基础。时至今天,我们所有受益于这点(接口与实现的分离)的程序员,仍然要感谢这一次具有历史意义的飞跃,使我们摆脱了曾经看来永不消逝的噩梦。不过正像B.S.所提及的那样,C++的每一次重大发展,都离不开成千上万优秀的开发人员在使用过程中的、自发的改革与创新。正是由于C程序员的历史的、创造性的形成了一种基于对象的思想,才有了C++的数据抽象机制。所以B.S.在采访中也曾多次表态,C++不会为了迎合所谓的潮流,以及所谓时髦的编程技术。相反,C++中所引入的每一项技术,可能不是最新、最cool的,但一定是由无数顶尖开发人员,经过无数代码以及项目实践的锤炼后,而最终被证明是对C++这门语言、编程艺术最实用的技术[1]。不管怎么说,第一次,我们把真实世界中存在的对象,从机器语言的海洋中抽象了出来。

“麻烦是永远不会消失的”,下一个将随之而来。现在有新的问题需要考虑,请深吸一口气,我们继续。

随着时代的发展,软件的规模在以几何级数增长。对于我们来说,数据抽象(单纯的类)机制也显得捉襟见肘了。因为对于一个产品级的软件项目来说,即便采用OB模式编程,我们也会发现程序中存在这成百上千的自定义类型,怎么样有效的管理他们呢?这又让像B.S.这样的大牛们多掉了几根头发。这一次,大牛们动真格的了,他们引入了类型继承的机制,也就是面相对象编程(OO, Object-Oriented Programming)。我理解派生和继承其实是一回事:对于基类来说,我们派生出了一个新类;而对于派生出的新类来说,他是继承于基类。突然之间,一个平面的世界变得立体了!以前所有的自定义类型都有相同的地位,数量的增多,好比草原上的野草,铺天盖地的横向发展。但如今,我们得益于类的继承,可以使类的逻辑关系有了纵向的发展,现在我们可以创造一棵大树,而且由此而创造出一片森林(当然,如果需要的话。一般来讲几棵或十几棵这样的大树,就够我们忙活的了)。这个过程仿佛我们把以前分散的人群,在组织的约束下组建成了一个军队,其威力不可同日而语。同时,这种机制也有个优秀的“副产品”——他使得“接口和实现的完全剥离”成为了可能。这一次,我们从有着紧密联系的各种类型当中,抽象出共同的接口以及实现。

如果说以上的种种机制,还都属于“破剑式”或者“破刀式”之类的“有招”的范畴的话,请你再深吸一口气,因为接下来的是终极必杀,独孤九剑的终极境界:“无招胜有招”。

这下,连类型本身也被抽象了!因为在语言中,有一部份是与类型无关的。比如“容器”,像C中的数组,C++中的vector;比如一些算法,例如 search, sort, count,等等,他们都与所操作的对象类型是无关的。现在我们有很多、非常多的类型,难道要为他们每个都重载一个容器或者算法么?天啊,这是Mission Impossible II。在B.S.等大牛们前额的头发又掉了几根以后,问题终于有了解决,那就是传说中的范型编程(GP, Generic Programming)。对于函数或者class,我们可以把“类型”当作一个参数进行传递、甚至返回[2]。对,也许你已经猜到了,这一回合,我们把实现中的容器、算法,从形形色色的类型当中抽象了出来,形成语言中一个独立的组成部分。

好了,现在你可以吐口气了



[1] 以上内容都是个人对B.S.的言论的理解,并不代表B.S.的本人的想法。关于B.S.的最新言论,可以参见:http://www.research.att.com/~bs/,另外,B.S.写的一篇关于C++发展史的文章,详细讲述了C++为什么成为了今天的C++,而没有成为很多人所猜测的,另外的C++ 或者是Cjava。有兴趣的话,你也可以找来看看。

[2] 是的,我知道,这是一种非常不专业的表述方法,请原谅。但是我个人认为他从某个方面简单明了的说明了模板机制的作用,所以我自作主张得采用了这样的表述方式,希望大家不要以专业的眼光进行批判。

 

<v:shapetype id="_x0000_t75" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:spt="75" coordsize="21600,21600" stroked="f" o:preferrelative="t"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" o:extrusionok="f" gradientshapeok="t"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics