2007年2月26日 星期一

Effective C++

很多程序员对牛人们谈论编程经验和感想的书籍顶礼膜拜,例如市面上种种《xx缄言》,《xx夜里睡不着觉》,《高质量xx》,以及老外写的一些诸如《xx陷井与缺陷》,《Effective xx》,甚至还觉得不过瘾,又来个《More Effective xx》。不知道以后会不会再出《More and More Effective xx》,《More and More and More Effective xx》,然后一直就这样more下去,子子孙孙无穷匮。

出于好奇和对牛人以及伪牛人出书的敬佩,我也看过这些流行的小书。然后不由得想起有人曾对刘墉的文章的一句评价:“吃饱了饭,喝了杯凉水,然后放了个屁。” Bjarne Stroustrup是我心目中真的猛牛,在他的《The C++ Programming Language》一书第二版的序中,曾说过这样一句令我感动的话。 “这里的叙述仍然是针对有经验的程序员,并努力不去轻视他们的智慧和经验。” 作为一个自以为是的人,我希望得到这种尊重。

其实对于语言的学习,只要你仔细阅读语言的权威书籍,认真实践,并勤于和善于思考,很多xx的经验,不言自明。Bjarne说要写出一个好程序需要智慧、品位和耐性,万分赞同。关于如何避免在C++中依旧使用C风格,以及有效使用C++进行编程,Bjarne已经给出一些很好的忠告。胜似金玉良言。我想摘录出来,以供借鉴。其中interface一词,译者把它译为“界面”,而我觉得这里译为“接口”更妥当一些,便改为接口。另外在抄这些条目的时候,忍不住做了一点注释。

给C程序员的建议

一个人对C了解得越好,在写C++程序时大概就越难避免C的风格,并会因此丢掉某些潜在C++的优势。这里是几个有关的要点,在这些地方做同样的事情时,在C++里存在比C更好的方式:

[1]在C++里几乎不需要用宏。用const或enum定义明显的常量,用inline避免函数调用的额外开销,用template去刻画一族函数或者类型,用namespace去避免名字冲突。
(抄袭者注:宏使得代码不易于理解和维护,有更多潜在的陷井,增加了出错的可能性。这个建议在C语言中也有一定的适用性,并且gcc的扩展使得C语言也支持inline。)

[2]不要在你需要变量之前去声明它,以保证你能立即对它进行初始化。声明可以出现在能出现语句的所有位置上,可以出现在for语句的初始化部分,也可以出现在条件中。
(抄袭者注:在使用前定义变量而不是先定义好要用的所有变量再开始操作语句,这样使得代码可读性更好,并且不容易出错。在C中,对ANSI标准支持不好的C编译器,不允许在一个代码块中已经开始执行语句的位置定义变量。但如果编译器支持,那么在C语言中也应当采用这个建议。)

[3]不要用malloc()。new运算符能将同样的事情做得更好。对于realloc(),请试一试vector()。
(抄袭者注:new比malloc更加灵活,表达能力更强。使用new的代码常常更加简短,并且避免了“强制”这样的不良风格。)

[4]试着去避免void*、指针算术、联合和强制,除了在某些函数或类实现的深层之外。在大部分情况下,强制都是设计错误的指示器。如果你必须使用某个显示的类型转换,请设法去用一个“新的强制”,设法写出一个描述你想做的事情的更精确的语句。

[5]尽量少用数组和C风格的字符串。与传统的C风格相比,使用C++标准库string和vector常常可以简化程序设计。
(抄袭者注:C++在语言级别上提供了进一步的抽象,使得程序设计更加简化,维护更加容易。但无论使用C还是C++,使用安全而高效的库,总是比自己编写相关算法更好。因为这样不仅提高了生产效率,提高了代码的复用程度,而且使程序代码更简短,易于维护。所以尽量使用标准库中的容器和泛型算法,而不是自己处理低层的实现。即使自己可以将代码编写得和标准库一样高效和安全。)

最重要的是,试着将程序考虑为一组由类和对象表示的相互作用的概念,而不是一堆数据结构和一些去拨弄数据结构中二进制位的函数。


使用C++的一些忠告

要写出一个好程序需要智慧、品位和耐性。你不会第一次就能把它搞好的。试验!

[1]在编程序的时,你是在为你针对某个问题的解决方案中的思想建立起一种具体表示。让程序的结构尽可能地直接反映这些思想:
[a]如果你能把“它”看成一个独立的概念,就把它做成一个类。
[b]如果你能吧“它”看成一个独立的实体,就把它做成某个类的一个对象。
[c]如果两个类有共同的接口,将此接口做成一个抽象类。
[d]如果两个类的实现有某些显著的共同东西,将这些共性做成一个基类。
[e]如果一个类是一种对象的容器,将它做成一个模板。
[f]如果一个函数实现对某容器的一个算法,将它实现为对一族容器可用的模板函数。
[g]如果一组类、模板等互相之间有逻辑关系,将它们放进一个名字空间里。

[2]在你定义一个并不是实现某个像矩阵或复数这样的数学对象的类时,或者定义一个低层的类型如链接表的时候:
[a]不要使用全局数据(使用成员)。
[b]不要使用全局函数。
[c]不要使用公用数据成员。
[d]不要使用友元,除非为了避免[a]或[c]。
[e]不要在一个类里面放“类型域”;采用虚函数。
[f]不要使用在线函数,除非作为效果显著的优化。

请记住,这些忠告只是粗略的实用规则,而不是万古不变的定律。它们只应使用在“合理的地方”。从来就没有任何东西能够替代智慧、经验、常识和好的鉴赏力。

标签:

0 条评论:

发表评论

<< 主页