本来只想对C++赞叹复赞叹,后来就失控了,接着情绪化了,最后终于开始爆走,语无伦次。
平心而论,C的而且确小巧精致,一切通通透透。老夫真心喜欢用它来编码,但一旦动用真格了,就立马叶公好龙,就会怀念C++的种种好处,class、 template、 virtual、 析构函数、甚至异常、const、引用等等,原来,离开了之后,才明白你的种种美妙动人之处,因此,朕已决定,有生之年,假如还在编码,那么C++,在心目中的,将是无可替代,它的一切,即便缺点,也是那么地令人回味无穷。因为它的一切,将自由贯彻到底,充分尊重用户的选择,不轻易剥夺用户的权利,更不强求用户用什么样的方式做设计。所谓自由的世界,独立的人格,手持C++利器,虽不敢说横行天下,但起码能愉快地编码。只有C++,当一个人独立使用,如此的耐人寻味,历久常新。多人一块开发,简直是大灾难,没必要的封装,种种自制的破烂轮子(前几年,出自本座手中的轮子不计其数,基本上惨不忍睹),错综复杂,交叉引用的类关系。这在其他语言中难以出现的怪现象,在C++中,平常得很,再一次证明了C++的博大精深,包罗万象。不说别的,就说C++中的最负盛名GUI框架MFC,其类层次的设计,糟糕透顶,而BCG的代码注入,毫无创意,笨拙无比的命名,垃圾般狗屎般的代码堆积,可怕的内存消耗,令人眼界大开,MFC的资源消耗已经够厉害,相比之下,居然显得那么节俭,而用BCG开发界面,居然比C#又或者JAVA做出来的软件,还不卡,这一切,都证明了C++过人之处。爱死你了,C++。
近几年来看到某些人不知出于何因,对C++横加指责,说什么论效率不如C,论高级特性又不如其他的动态语言,实在莫明奇妙。说什么C++中的inline、继承、template破坏了模块的分离,“用C语言1000行源码能完成的工作千万不要用C++重写!”,实则用C++来写根本就无须1000行,并且可以精简那些字数多的代码行,并且还更加易读易懂,更加容易维护,效率或许还能更快一点点,得益于内联。如果还觉得用C++写1000行代码没有C那么漂亮,那只证明阁下没能力驾驭C++,请不要对C++乱加指责。他们那些所谓的C高手的代码,到处指针飞舞,又长又臭一再重复的表达式(本该内联大显身手),着实让人难受,当然,不否认他们的精妙设计。
纵观他们对C++非议之例子,无一不暴露出其设计上的缺陷,本该成员函数指针大显伸手,他们却用上了虚函数;Template模式的函数(顺序依次,调用几本虚函数),本该做成全局函数,硬是整成员函数;多继承中的钻石抽象基类不该有任何东西,他们却偏要放某些东西,最后没办法,在虚继承中纠结。……所有这一切根本无损于C++,却只显现出他们的愚蠢与无知。想展现自己也言行独立,到头来却做出拾人牙蠢之事。其实,他们更应该感谢C++,是C++的包容,才容许了如此丑陋的设计。本座平生最不齿这群宵小,自己毫无主见,风闻名人几句惊世骇俗之话语,就跟着瞎起哄,国人的毫无道理的盲目跟风,由来已久,也不必细表了。那些所谓的C高手,觉得用C能做出精妙的设计,为何用起C++就不行了,其实他们大可“用C做设计,用C++编码”,这样,根本就不会影响他们的伟大杰作构思。
并且要做到如同C那样的高效,C++中完全没有问题,完全可以放下身段,将C++的抽象降低到C那样的级别,在没有独立完整的概念之前,或者是没有很好的理由,绝不用类来封装代码,禁用慎用C++的一切高级特性,好比虚函数、继承、异常等。任何语言特性都可以写出垃圾代码,也容易用得不好,但不可因为这样,就否定此种特性的价值。特性作用越大,就越微妙,就越容易滥用误用。即此而观,C++中,应该以class最为难用,此关一过,必定神清气爽。
的确,C中,你可以也必须面对一切细节,在这种恶劣的环境下,手上能用的武器,也只有函数、结构体、数组和宏,程序员的潜能就这样被迫出来,爆发出来了,做出最合乎本质的设计,而这几样简单武器,互相组合,居然可以用得如此出神入化,其效果鬼斧神工,巧夺天工,直可惊天地,泣鬼神,手法更是精彩缤纷,巧妙绝伦,令人目不接暇,但是,不管如何,始终缺乏管理细节的有效武器。
鄙人最惊叹C++的一强悍之处,对于各种匪夷所思的变态问题,会有更加变态的解决方式,而且还不止一两种,更可见其灵活多变自由丰富的个性,但众多迥异特性又能如此和谐的共存,为什么?窃以为C++是强类型的静态语言,虽然提供多种语言工具以让码农愉快轻松地编码,尽可能地在编译时期发现更多错误,各种微妙的语言特性不过是为了帮助码农愉快高效地编码,少出错,他们可以用这些语言工具整理组织C的各种凌散的表达式。
因为C中虽然能直面一切细节,却缺乏管理细节的语言工具。所有C中的细节,几乎可通过C++的各种丰富特性妥善整理,而效率的损失又甚少,并且,在其强大的静态系统的分析,能多发现点问题。但是强类型只是工具而已,必须善加利用,但C++的码农不会受束缚,必要的时候,大可突破。鄙人就曾经实现了一个微型的动态系统,对象之间没有用层次关系,都是平等的,但之间又能互相组合装配拆除,达到多继承的效果,又没有多继承的各种问题。虽然语法上别扭点,但习惯了就感觉挺不错。
要看到C++的对C代码的变态重组,为此,随便举例,qsort是代码上的典范境界,能排序所有的数组,只要提供了元素之间的比较函数,就能快速地排序,实至名归。但它是弱类型,其正确性全靠程序猿手工输入,参数出错了,编译器也检查不出来,当然C高猿不大容易出错。只是,依赖于C++强大类型推导威力,通过template整成以下样子,既不限制qsort的包容性,又不损失任何一点点效率
template<typename _Ty>
inline void Sort(_Ty* pItems, size_t nItemCount, int (__cdecl* funcCompare)(const _Ty&, const _Ty&))
{
int (__cdecl * _PtFuncCompare)(const void *, const void *);
union_cast(_PtFuncCompare, funcCompare); // 为忽弄编译器的强类型检查
qsort(pItems, nItemCount, sizeof(_Ty), _PtFuncCompare);
}
但已经是强类型的了,C++猿用起来就不大容易出错了,并且元素的比较函数也更加容易编写,没必要再用指针了,个人而言,引用比指针好,最起码少敲一下键盘,那行代码的长度可减少了一个字符。这样,用起来不是更爽吗?
又好比消息循环,判断消息类型,一遍又一遍地写着重复的表达式,好比,msg.message==WM_LBUTTONDOWN,不好玩,干脆class一CMsg,继承自MSG。好比这样:
class CMsg : public MSG
{
public:
bool Is(DWORD nMsg) const{ return message==nMsg; }
};
于是以上的那行判断语句,就精简成msg.Is(WM_LBUTTONDOWN),感觉应该好点吧。这两例的代码整理手段,对C++来说稀松平常,但C中就做不出来了,大概也只能用宏了,但宏的问题,大家也知道。
又有人说,C++高手的修成要经过两次转换,从C到C++,然后从C++回复C,实在异想天开,不值一晒,舍弃C++的强大类型检查,欲与一切细节肉博,吾不见其高明。这不是什么C++高手,充其量也只是C高手,其苦心孤诣在C中模仿C++的面向对象的伎俩,用C++来表达,不过小菜一碟,并且还不失强类型检查,必要时,只须用联合体或类型转换忽悠编译器。那些回归C的高猿的C++代码,其实,不甚精致。所以,大家也不必理会。只须老老实实地做出简简单单的设计,然后再用C++组织管理各种细节,大可将代码写得漂漂亮亮干干净净。
要谨记的是,只用那些熟悉有把握的语言特性,对于每一个用到的C++关键字,一定要清楚其背后的机制并且由此所带来的各种副作用。最难用的就是class了,毫无必要的封装, 比赤裸裸的代码更加丑陋,请优先选择非成员函数。封装的出现,是因为代码的一再重复出现的需要,而并非想当然地推理演绎。只要是重复代码,不管是一行表达,连续多行,分散跨行,都可以给予包装在一起,只需一个函数调用。
再次重温C++的核心设计,尽可能利用静态强类型,尽可能地在编译期中找出程序的错误,提供多种丰富特性,协助码农充分地发挥强类型的一切优点,对抗一切细节,对抗一切重复代码,并且不必付出任何不必要的代价。当然,强类型只是忠实的奴仆,完全不必因为它而迁就你的设计,想要忽悠它,方法多种多样。 有人说,C++的语言特性太凌散,不系统,好像打补丁似的。但鄙人觉得挺好的,特性分散,各自为政,可随意自由组合,你讨厌某个特性,大可不必理睬,它就静静地站在一旁,丝毫不影响你的代码,这不就是设计的最高境界吗。
好了,终于狠狠地出了口恶气。在下承认很情绪化,有失高手风范。