第三章命名规则
比较著名的命名规则当推Microsoft公司的“匈牙利”法,该命名规则的主要思想是“在变量和函数名中加入前缀以增进人们对程序的理解”。例如所有的字符变量均以ch为前缀,若是整型数则用n为前缀。例如nWidth, chText, fTax. 但笔者认为这种表示方法过于烦琐,而且未必真能有效增进理解,因此不建议用匈牙利法。
良好的命名规则可便于记忆和理解。但是什么是好的命名规则并没有一个标准,程序员之间也很难达成意见一致,在同一个项目组中相对做到统一就可以了。
【规则3-1-1】标识符应当直观且可以拼读,可望文知意,不必进行“解码”。
标识符最好采用英文单词或其组合,便于记忆和阅读。切忌使用汉语拼音来命名。程序中的英文单词一般不会太复杂,用词应当准确。例如不要把CurrentValue写成NowValue。
【规则3-1-2】标识符应该用最少的字符表达最准确的意思。
循环变量可以用i, j, k这些变量。利用一些很明了常用的缩写减小长度,如tmp(temp), flg(flag), cur(current),val(value),message(msg)
char *pText;
BOOL bSaved;
int strLen // string length
CRect curRect // current rectangle
string msg //message
|
【规则3-1-3】命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
例如Windows应用程序的标识符通常采用“大小写”混排的方式,如AddChild。而Unix应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起用。这里建议用”大小写”混排, 即使要使用下划线_,下划线数量不能多于一个。
【规则3-1-4】程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但会使人误解。另外不要用大小写的不同区分两个变量。
【规则3-1-5】变量的名字应当使用“名词”或者“形容词+名词”。
float value;
float oldValue;
float newValue;
|
【规则3-1-6】全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。类的成员函数若宾语为对象本身,可省略宾语
DrawBox(); // 全局函数
box->Draw(); // 类的成员函数
|
【规则3-1-7】用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
int minValue;
int maxValue;
int SetValue(…);
int GetValue(…);
|
【建议】多动脑筋想一个好的命名,不要偷懒。尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。
【规则3-1-8】类名和函数名用大写字母开头的单词组合而成; 变量和参数用小写字母开头的单词组合而成,单词之间用大写开头便于分割; 常量全用大写的字母,必要时用下划线分割单词。
class CNode; // 类名
class CLeafNode; // 类名
void DrawBox(void); // 函数名
void SetValue(int value); // 函数名
int drawMode;
string oldText
|
【规则3-1-9】静态变量加前缀s_(表示static)。如果不得已需要全局变量,则使全局变量加前缀g_(表示global),在指针变量前加一个p, 在布尔类型前加一个b.
static double s_taxRate;
CPen *pOldPen;
bool bSaved;
int g_howMuchMoney; // 全局变量
|
【规则3-1-10】类开头可以考虑用大写C标注。类的数据成员加前缀m_(表示member),这样可以避免数据成员与成员函数的参数同名。
void Object::SetValue(int width, int height)
{
m_width = width;
m_height = height;
}
|
【规则3-1-11】为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。例如三维图形标准OpenGL的所有库函数均以gl开头,所有常量(或宏定义)均以GL开头。
结构体 MGAXIS, MGLINESTYLE, MGPLOT // GM前缀: MathGraph
|
第四章表达式与语句
【规则4-1-1】如果代码行中的运算符比较多,用括号确定表达式的操作顺序,避免使用默认的优先级。这样比较明了,毕竟不是每个人都记得牢优先级。
if ((a | b) && (a & c))
|
【规则4-1-2】判断布尔值的表达
if (flag) // 表示flag为真
if (!flag) // 表示flag为假
|
【规则4-1-3】数值与0值的比较。将整型变量用“==”或“!=”直接与0比较,但不可将浮点变量用“==”或“!=”与任何数字比较。
千万要留意,无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。
if (nValue == 0) //nValue为整型
if (nValue != 0)
|
if ((x>=-EPSINON) && (x<=EPSINON))
//其中EPSINON是允许的误差(即精度)。
|
【规则4-1-4】应当将指针变量用“==”或“!=”与NULL比较,表示待比较的是个指针。建议把NULL前置,避免错用赋值语句把NULL赋值给指针
if (NULL == pDC) // 防止if ( pDC = NULL)
|
【规则4-1-5】不要在for 循环体内修改循环变量,防止for 循环失去控制。
【建议】建议for语句的循环控制变量的取值采用“半开半闭区间”写法(由于数组索引从0开始)。
x值属于半开半闭区间“0 =< x < N”,起点到终点的间隔为N,循环次数为N。
if(i=0;i<N;i++)
【规则4-1-6】每个case语句的结尾不要忘了加break,否则将导致多个分支重叠(除非有意使多个分支重叠)。在case末尾最好加上default分支。每个case分支尽量不要超过20个语句。
【规则4-1-7】在C++ 程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。在类里面的常量用枚举类型。常量全部用大写字母
const double PI = 3.1415926
|
class A
{…
enum { SIZE1 = 100, SIZE2 = 200}; // 枚举常量
int array1[SIZE1];
int array2[SIZE2];
};
|
【规则4-1-8】define语句中的变量值必须加上完备的括号, 减少错误可能
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
第五章函数设计
【规则5-1-1】参数的书写要完整,不要贪图省事只写参数的类型而省略参数名字。
【规则5-1-2】参数命名要恰当,顺序要合理。如果参数是指针,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被意外修改。
例如编写字符串拷贝函数StringCopy,它有两个参数。如果把参数名字起为str1和str2,例如
void StringCopy(char *str1, char *str2); //不良的命名
应为 void StringCopy(char *Dest, const char *Src);
|
【规则5-1-3】如果输入参数以值传递的方式传递复杂对象,则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。
【建议】避免函数有太多的参数,参数个数尽量控制在5个以内。如果参数太多,在使用时容易将参数类型或顺序搞错。可以把几个参数合并成一个结构。
【规则5-1-4】在函数体的“入口处”,对参数的有效性进行检查。很多程序错误是由非法参数引起的,我们应该充分理解并正确使用“断言”(assert)来防止此类错误。还要检查通过其它途径进入函数体内的变量的有效性,例如全局变量、文件句柄等。
【建议】函数的功能要单一,不要设计多用途的函数。
【建议】函数体的规模要小,尽量控制在100行代码之内。
【建议】在函数内部产生的临时堆内存块和一些对象关联,一般在函数的末尾删除,以方便检查。
void Func()
{
int *pTemp = new int[50];
.....
delete[] pTemp;
}
|