《高质量C++/C编程指南》陷阱 2

Created @ 2013-04-12, r1 rev 2013-04-12, markdown @ 2015-09-14.

http://tieba.baidu.com/p/2262386913

本文提到的“原文”同样是指《高质量C++/C编程指南》。 原文链接已经修正。

(*)“以实际经验出发”并不和内容有误矛盾。即便实际经验是符合事实的,对于不够有经验的读者还是有相当的危害。

(**)文章中指出的错误大多是和公认的常识相悖,即便标准能够提供更精确的解释。即便没有标准,错误也不应该出现。

1

“作者的本意是想说明实际操作中通常的组织代码方式。”

↑虽然比较合理的可能的原意能够被有经验的用户通过下文猜出来,但是这个表述无疑是错的。即便不管标准定义,“程序”的概念在C++中是清晰的。声称一个程序通常组织为“两个文件”,是显然的误导。

1.2.1

这里需要补充,实际是否应该使用这种风格取决于具体需要。

类模版因为分离定义导致代码过于复杂所以往往不适用,但如果能保证可维护性也不是不能用(如 libstdc++ 拆分的 .tcc )。

而除了模版外 inline 函数也适用。

甚至有实用的不用 inline 或非模版函数的 header-only 库(如 CImg ——虽然我内部依赖组织得不怎么样,嘛,题外话了)。

3.1

命名原则应该足够清晰。

需要指出,只强调“直观可以拼读”往往不是最佳实践。当一个“直观”标识符长度过长时就不能使用:

(1)实现不支持的情况。在ANSI C89只规定较少的标识符长度支持。在C++中这种情况的影响较少。

(2)大量出现,过长的标识符影响阅读时。一般拟定通用的缩写,在文档(至少注释)说明。

3.2

没记错的话 namespace 加入 C++ 是在 90 年代前期提出的,2001 年的主流编译器支持应该不成问题( VC6 也支持)。这不是一个很容易实现错而需要避免使用的特性。

考虑到即便是很久以后不少用户对 namespace 的使用也有因为各种原因有意无意的回避反而导致放弃使代码更清晰潜力(例如 box2d 和旧版 FLTK ),在这里补充是有必要的。

4.3

已修正。

链接是BS的个人主页。失效似乎是最近几个月的事情。

5

由于历史原因,“常量”的用法比较混乱,具体含义往往需要通过上下文推测。这里对标题的解释不充分显著地增强了误导的可能性。

这里是非常基础的内容,不应该有放任明显混淆这样的低级错误。

“完全”当然不可能。是否“尽量”,也要看需求。例如有时需要用于条件编译的编译时确定的整数值,const在这里无能为力。

6

没找到在哪里说“帮助新手区分指针和引用”。出处?

帮助新手区分指针和引用完全不必要也不应该使用这种有问题的说法。

6.3.1

(1)的确需要补充。

(2)原文没有指出就是 assert 。 从契约式设计上来说,用 assert 是一种常见的实现,但使用在运行时抛出异常等其它手段有时也是可接受的手法。 而 C++11 补充的 static_assert (以及之前的模拟)也算,尽管适用范围受限。(题外话,assert 就没法 constexpr 了,这点大概算是 C++11 的缺陷。)

6.3.2

这点确实是错误。已补充修正。

不过需要另外指出,“临时变量”的说法是有问题的。C++中的变量是指声明引入的对象或引用,临时变量中的“变量”很多时候无法作为这个含义。从下文来看,是“临时对象”之误。

这样,就有一个硬伤。表达式中使用模拟类类型的对象初始化得到的一个非类类型右值,不是临时对象。

return int(x + y); // 注意:不创建临时对象。

至于后面“已经说过”的问题,重点是刻意区分“值”的意义。这又是一个混乱的概念,尽管严格意义上相对单一。不应该在此处引入增加误导可能。(我很怀疑原作者是否有意识到这点。)

7

和本文无关,不过提一下,根据 wikiquote ,这句不是 Bill Gates 说的。

7.1

这点是基础概念问题,和具体实现无关。 C 语言也需要讨论类似问题,虽然说法不同。

10.2

从 OOD 的角度来看是这样没有错,但注意文章强调的是编码而不是设计上的质量,说的是 OOP 。

从 OOD 到 OOP 的映射过程不是单一简单的,毕竟使用的不是建模语言。尤其是对 C++ 来说,不少语义和 OOD 所强调的抽象不相吻合,也不能方便地实现。

简化 OOD 到 OOP 的过程或许正是 Java 之流体现价值的重点之一。然而,这样的选择是以牺牲可能实现的灵活性为代价的。而这种灵活性正是 OOP 用户欠缺与需要重视之处。

这样的使用可以说是“一种技巧”,但类似地也有其它一些特性,如 class-scope using 。 C++ 为什么不抛弃这些看起来不符合 OO 方法学的特性?我认为主要并不是兼容性的问题,而是在设计上鼓励语言的用户有权利选择自由灵活的表达方式。 就这里的问题而言, private 继承的含义是“用……(基类)实现”,即便 OOP 角度上不是典型的组合,同样可以是 OOD 中组合的映射结果。

results matching ""

    No results matching ""