《高质量C/C++编程指南》学习笔记

这本书只有短短100页,可是却可以称得上是脍炙人口。一年前初读此书时就感觉受益良多,而今再次重读,仍然不肯停顿一口气读完。针对书中指出的一些编程规则和建议,,摘录下个人认为比较好的部分。第1章 文件结构用 #include <filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。用 #include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。第2章 程序的版式一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。if、for、while、do等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}。这样可以防止书写失误。尽可能在定义变量的同时初始化该变量(就近原则)。长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。第3章 命名规则标识符应当直观且可以拼读,可望文知意,不必进行“解码”。命名规则尽量与所采用的操作系统或开发工具的风格保持一致。例如Windows应用程序的标识符通常采用“大小写”混排的方式,如AddChild。而Unix应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起用。变量的名字应当使用“名词”或者“形容词+名词”。第4章 表达式和基本语句不可将布尔变量直接与TRUE、FALSE或者1、0进行比较。假设布尔变量名字为flag,它与零值比较的标准if语句如下:if (flag) // 表示flag为真if (!flag) // 表示flag为假应当将整型变量用“==”或“!=”直接与0比较。假设整型变量的名字为value,它与零值比较的标准if语句如下:if (value == 0) if (value != 0)不可模仿布尔变量的风格而写成if (value) // 会让人误解 value是布尔变量if (!value)不可将浮点变量用“==”或“!=”与任何数字比较。应当将指针变量用“==”或“!=”与NULL比较。指针变量的零值是“空”(记为NULL)。尽管NULL的值与0相同,但是两者意义不同。假设指针变量的名字为p,它与零值比较的标准if语句如下:if (p == NULL) // p与NULL显式比较,强调p是指针变量if (p != NULL)每个case语句的结尾不要忘了加break,否则将导致多个分支重叠(除非有意使多个分支重叠)。不要忘记最后那个default分支。即使程序真的不需要default处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了default处理。第5章 常量在C++ 程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。第6章 函数设计const数据成员的初始化只能在类构造函数的初始化表中进行,例如 class A{…A(int size);// 构造函数const int SIZE ;};A::A(int size) : SIZE(size) // 构造函数的初始化表{…}A a(100); // 对象 a 的SIZE值为100A b(200); // 对象 b 的SIZE值为200如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。return语句不可返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。例如 char * Func(void){char str[] = “hello world”; // str的内存位于栈上…return str;// 将导致错误}第7章 内存管理用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。用malloc申请一块长度为length的整数类型的内存,程序如下:int *p = (int *) malloc(sizeof(int) * length);第8章 C++函数的高级特性成员函数被重载的特征:(1)相同的范围(在同一个类中);(2)函数名字相同;(3)参数不同;(4)virtual关键字可有可无。覆盖是指派生类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派生类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有virtual关键字。参数缺省值只能出现在函数的声明中,而不能出现在定义体中。关键字inline必须与函数定义体放在一起才能使函数成为内联,仅将inline放在函数声明前面不起任何作用。第9章 类的构造函数、析构函数与赋值函数 A(void);// 缺省的无参数构造函数A(const A &a);// 缺省的拷贝构造函数~A(void);// 缺省的析构函数A & operate =(const A &a); // 缺省的赋值函数如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。例如 class A{…A(int x);// A的构造函数};class B : public A{…B(int x, int y);// B的构造函数};B::B(int x, int y): A(x)// 在初始化表里调用A的构造函数{…} 类的const常量只能在初始化表里被初始化,因为它不能在函数体内用赋值的方式来初始化。偷懒的办法处理拷贝构造函数与赋值函数 偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。例如:class A{ …private:A(const A &a);// 私有的拷贝构造函数A & operate =(const A &a); // 私有的赋值函数};在编写派生类的赋值函数时,注意不要忘记对基类的数据成员重新赋值。第10章 类的继承与组合若在逻辑上B是A的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性。第11章 其它编程经验如果输入参数采用“指针传递”,那么加const修饰可以防止意外地改动该指针,起到保护作用。当心那些视觉上不易分辨的操作符发生书写错误。我们经常会把“==”误写成“=”,象“||”、“&&”、“<=”、“>=”这类符号也很容易发生“丢1”失误。然而编译器却不一定能自动指出这类错误。变量(指针、数组)被创建之后应当及时把它们初始化,以防止把未被初始化的变量当成右值使用。当心变量的初值、缺省值错误,或者精度不够。当心数据类型转换发生错误。尽量使用显式的数据类型转换(让人们知道发生了什么事),避免让编译器轻悄悄地进行隐式的数据类型转换。当心变量发生上溢或下溢,数组的下标越界。当心忘记编写错误处理程序,当心错误处理程序本身有误。当心文件I/O有错误。避免编写技巧性很高代码。不要设计面面俱到、非常灵活的数据结构。如果原有的代码质量比较好,尽量复用它。但是不要修补很差劲的代码,应当重新编写。尽量使用标准库函数,不要“发明”已经存在的库函数。尽量不要使用与具体硬件或软件环境关系密切的变量。把编译器的选择项设置为最严格状态。

如果可能的话,使用PC-Lint、LogiScope等工具进行代码审查。

转载请注明出处!

伟人之所以伟大,是因为他与别人共处逆境时,

《高质量C/C++编程指南》学习笔记

相关文章:

你感兴趣的文章:

标签云: