zoukankan      html  css  js  c++  java
  • 【好文转载】看着C++远去

    云风的blog

    https://blog.codingnow.com/2007/02/cplusplus.html#comments

    看着 C++ 远去

    昨天试着维护几年前写的一个 C++ 库,只是增加一点东西。以那个时候我的眼光看,这个库设计的不算太差。这几天用的时候需要一些新功能,修改代码的话,有点担心引起不必要的麻烦。所以我决定从其中一个类继承下来,增加我要的东西。

    大约花了半个多小时完成我需要的功能,由于 namespace 嵌套较多,修改编译错误又花掉了一些时间。当编译通过后,代码基本工作正常了。

    事情做完了却有一点恶心。

    我已经半年多没碰 C++ 了,习惯回 C 以后,怎么看 C++ 都有种说不出来的厌恶。这一年多来,我在不同的场合表达或听到过 C++ 语言的尴尬。现在无论怎么回忆,也找不回当年对 C++ 那种无比热爱的感觉了。

    ps. 据说 C++ 0x 要加入 gc。总算它没有在 template 的滥用上渐行渐远,算是一点欣慰吧。

    我觉得,如下陈述,也算是所有支持OO的语言的通病吧:
    所谓面向对象,从本质上说,是允许你去扩充这种语言本身的类型系统;所不同者,也就是究竟允许你的扩充可以在多大程度上去模拟原生类型。

    各种支持OO的语言里,C++无疑是做的最为彻底的一种(我觉得不用加“之一”了^_^);而其他如c#、java等等,则都做了更多限制——这些限制包括“禁止运算符重载”以降低类型模拟的层次和难度、“取消指针运算”以降低原生类型本身的复杂度(从而在另一个角度降低用户类模拟原生对象的难度),如此等等。


    但,无论如何,只要在一定程度上“允许模拟原生类型”,那么同时也就提出了另一个要求,即:你必须模拟好该语言的原生类型,至少也要描述清楚你的类和原生类型间的不同之处。

    对于java、c#之类“阉割版”(没有贬义)面向对象语言来说,这个模拟并不很难——虽然不可避免地有点额外的小麻烦。

    但对C++这个雄心勃勃的语言来说,情况就完全不一样了——你包装了个复数类?好吧,重载四则运算吧——它必须能够与其他已知未知的数值类型互动。
    像java一样重载一大堆的equals?然后再在扩充了其他如有理数类时增加新的重载函数?
    恶心。

    于是,你不得不动用泛型(虽然java禁止了运算符重载,但基于现实需要,它很快也要支持泛型了)。


    于是乎,犹如老鼠拖木锨般,虽然初始目标是想做一个很小巧的东西,最后却发现自己不得不为了将其融于语言本身(或者说让人能以一致的风格使用),而不得不写出越来越多的东西。
    这方面,java、C#要好不少,毕竟没有那么复杂的原生类型或/和不允许全面模拟原生类型。
    但从本质上来说,情况并没有改变;反而是付出了性能和表达能力上的代价。
    并且,java终于也要支持泛型了。


    越是追求技术,越是追求尽善尽美,OO语言用起来就越是痛苦——这个东西能否拷贝?暂时似乎还用不到,禁了吧,以后再写(不禁,就是bug!)。

    诸如此类本不必管的无聊问题,程序员却丝毫不能怠慢——为避免他人误中“边际效应”陷阱,在设计新类时,我们就不得不写出更多的代码。


    从本质上说,OO语言是一个frame work,它封装了面向对象这个设计模式——c写的unix有个泛文件概念,一切最终可归结到输入输出上的东西都是文件:谁能说它不是面向对象的设计思路呢?

    所以说,c、汇编,都可以是面向对象的;设计者可以根据实际需要裁剪,给出最为精巧简洁的方案。

    而OO语言,则强迫设计者使用语言给出的框架,做出完全面向对象的设计——java干脆不允许非对象的东东出现:这就在方案的可裁剪性上出现了问题。
    尤其是对于C++来说:写一个类,就要考虑是否允许它如原生类型般工作;写一个算法,就要考虑它能否一劳永逸地处理所有类似问题;倘想解决所有这些问题,最终就会归结到模板;要动用模板,就要考虑编译器支持能力,要学习最新的泛型技巧……

    总而言之:一旦你想设计一个自给自足的、完美的类,不知不觉间,程序的设计重心就从“解决实际问题”转移到“写一个通用库”上了。

    比如,在使用C时,仅仅为解决实际需要,为一个结构体写一个可完成工作的处理函数,是很自然很完美的;而到了C++中,这二者的结合有多丑陋,就不用多说了吧。

    换句话说,就是使用OO语言,非常容易陷入“过度设计”这个泥潭;尤其是对那些工程经验不是很足、并且喜欢钻研底层的人来说。

    即使工程经验很足,上面那种很实用的“半拉子类”,看起来也是极其恶心的。不如老老实实写成c结构体+一个处理函数的模式。

    OO和泛型,本质上是用来写库的(而且是设计良好的库);不问青红皂白就拿来做工程,怎么可能不恶心?

    虽然,用对了地方,它们真的很强大。


    滥用OO、泛型和设计模式,则是另一种恶心。

    我遇到过这样一个糟糕的设计:一个模式套一个模式,反正一眼看上去不知道他要干什么。等分解清楚了才发现:他一开始启动了10多个线程同时读取文件内容;然后等所有这些线程都完成了,启动10多个线程同时开始分析;再等所有线程都分析完了,再同时开10个线程写入数据库;等都写完了,重新开10个线程去读文件……

    该并行时不并行,不该并行乱并行(并行读磁盘,不越并行越慢才怪——特殊设计的大型存储系统除外);不过设计模式用的倒真溜,一口气上了5、6种。

    设计模式是好东西,但不是随便怎么用还都是好东西。OO、泛型亦然。

     

    从我们现在的项目来看 (几十万行代码,几百个源文件),C 语言写的模块更容易和人协作。

    这是C++的死穴,虽然我是无比欣赏boost的狂热者,但是更多的人没时间去搞明白boost

     
  • 相关阅读:
    Windows Phone 7 中常用Task
    设置Highchart柱子最大宽度( 让 highcharts支持maxPointWidth属性)
    Asp.Net MVC 使用FileResult导出Excel数据文件
    js获取网页高度
    使用window.addEventListener 和 window.attachEvent 判断浏览器
    slimscroll滚动条插件简单用法
    js中如何快速获取数组中的最大值最小值
    js 判断浏览器类型
    python使用ldap进行用户认证
    关于go声明切片的一些疑问
  • 原文地址:https://www.cnblogs.com/ageane/p/cxx2.html
Copyright © 2011-2022 走看看