公司程序员代码没有良好控制,为更好的进行程序项目管理,做以下要求。

By FreeKnightDuzhi

1:

编写功能模块前必须提交模块设计说明。

其中要求包括设计的动态流程图,静态UML图,状态图,数据流图,线程交互图,数据库设计,设计模式,模块交互图,限制条件,生命周期,安全性设计,效率优化设计,相关策划案,对其他模块或第三方库的依赖关系,提供的核心接口函数,预计开发周期。

若上述模块没有涉及的,可留空。

2:

头文件必须以.h或.hpp(除编辑器生成外,不允许.hpp文件)为文件后缀。 inline文件可以以.inl为后缀。 template文件可以以.tem为后缀。 脚本文件以相应的后缀使用,例如.lua, .python, .us, .as等 纯C程序定义文件使用.c 为后缀。 C++程序定义文件使用.cpp为后缀。特殊情况允许使用.cc和.cxx为后缀。

3:

头文件以及源文件内必须有版权和版本信息。要求如下:

/* * Copyright © 2010, 北京XX公司 All rights reserved. * 文件名称:filename.h * 简要说明:本文件的作用 * 当前版本:V3.0 * 作者:FreeKnight * 日期:2010-12-20 * 修改者:FreeKnight * 修改日期:2010-12-21 * 修改内容: 增加删减或修改的内容 * 修改时版本:V3.1 */

4:

头文件规则:

1> VC7.1版本以上可使用#program once,以下必须使用#ifdef #define … #endif 包括预处理块。 2> 先使用#include 格式引用标准库头文件。 3> 再使用#include “file.h” 格式引用非标准库头文件。 4> 引擎部的对外公开头文件,内部私有头文件,源文件必须分别存储三个目录内,便于发布。

头文件建议:

1> 不要在头文件内存放“定义”。 2> 避免在头文件使用全局变量。 3> 头文件内可以使用类,函数声明的,避免直接包含其他头文件。 4> 避免预编译头庞大,仅存放常用头即可。 5> 若是库代码,对外暴露的头文件和对内的预编译头文件建议区分开来。 6> 除非关联性极强的类和结构,建议单一类单一头文件,不要一个头文件内定义大量的类。

5:

源文件内每个函数定义结束后都要加空行。 一个函数内,逻辑密切的语句间不加空行,但逻辑不密切的语句间应加空行分割。 一行代码应当只做一件事情,以便添加注释。 if, for, while, do 等语句应当自占一行,执行语句不得紧跟其后。无论执行语句多短,都必须添加大括号,大括号各占一行。 对于&&,||进行操作时,每个分支应当以括号包含起来。 复杂的长表达式,也应当根据优先级使用括号包含起来。 代码行最大长度建议控制在60个字符以内,若超过,建议换行。换行时,建议操作符放在新行首部。 避免使用多用途的符合表达式。例如 if( d = ( a = b + c ) + e )

6:

除Get,Set,构造析构等极其明白易懂的函数外,函数应当加上注释。 个别函数参数或返回值有约定时,应给出注释说明。 函数体超过20行,应当在核心思想处给出注释。 函数的注释建议在函数上方专留一行编写,变量的注释可直接在参数声明或定义后本行编写。

7:

类的编写,建议以行为为中心,不要以数据为中心。

8:

命名要求使用匈牙利命名法。m_ s_ g_ ms_ gs_ l n f un dw b d s us h C++实现类以C开头,模版类使用T开头,接口类使用I开头,结构使用S开头。 不要使用 java 风格命名,避免下划线,多个单词的命名,首字母必须大写,命名尽量直观表达意思,不要金山词霸找生僻词。 Private函数可使用 双下划线 为首,例如 __PrivateFunc(); Proteced函数可使用 单下划线 为首。Public函数不需要。 函数参数建议以p_开头,以便于函数体内的局部变量进行区分。 变量名尽量使用 “形容词+名词” 格式,函数名尽量使用“动词+名词”格式。 常量和宏定义,使用全部大写的字母,以下划线分割单词。

9:

与零比较时。 整形 -> if( 0 == nValue ) if( 0 != nValue ) 布尔类型 -> if( !bValue ) if( bValue ) 指针类型 -> if( NULL == pValue ) if( NULL !- pValue ) 浮点类型 -> if(( fValue >= -EPSINON ) && ( fValue <= EPSINON ))

10:

循环效率。 for( int i = 0; i < 1000; ++i ) { for( int j = 0; j < 5; ++j ) { Do(); } }

不好。建议可能的话,将长循环放在内部,短循环放在外部。 若有if的话,可能的话,将if防止循环之外,避免if对循环的打断。 循环内尽量使用 for( int i = 0; i < n; ++i ) 而避免使用 for( int i = 0; i < n + 1; ++i ) 这样的全闭区间。

11:

迭代器,若迭代的是标准类型,则无妨。若为结构,则建议使用 ++Ite, 而避免使用 Ite++,可以减少构造的代价。

12:

尽全力避免goto.

13:

尽量使用 const int MAX_XXX = 100; 去替代 #define MAX_XXX 100 一些有关联的常量,应当给出关联,而非一个值。特别常量,可直接给出值,且在后面给出注释说明。例如

const unsigned int GRID_SIZE = 100;
const unsigned int GRID_IN_MAP = 25; const unsigned int MAP_SIZE = GRID_SIZE * GRID_IN_MAP; const float PAI_RECIP = 0.3183099 // π分之一

尽量使用内联函数替代宏函数。

14:

类内的常量不可以 const 定义。例如 class A { const int SIZE = 100; int m_nArray[SIZE]; // 不行,类未创建对象前,不知道SIZE多大。 } 若必须类内常量,可使用枚举。例如 enum{ SIZE = 100 };

15:

除函数指针外,函数建议在头文件内声明时,除了参数类型,也写上函数名。 无参数的函数建议使用void填充参数。 尽可能的准确使用 const . 若参数为自定义结构或类对象,建议使用地址传递方式,避免值传递带来的临时对象的构造和析构。

16:

不要脑残的返回栈上内存……!!!

17:

使用任何内存,数组,指针,变量都必须初始化!!!!!!!!

18:

对于参数传入的指针,要判断它是否为空!!!!!!!!

19:

写new的时候,一定要去写delete,再回来写逻辑。 可能的话,new这块内存所在的函数或类,应当负责delete这块内存,避免A创建分配内存,而由B去负责释放。特别是跨线程的管理更应三思而后行。

20:

数组为参数退化为指针就别让我再说了……

21:

重载和覆盖要警惕。

22:

尽量使用初始化表进行成员变量初始化,但要注意,若成员变量是自定义类,要确定类的构造顺序。 类中的const常量只能使用初始化表进行初始化,不能赋值初始化。 若类有继承关系,则子类必须在构造函数内显式的调用基类的构造函数,依旧是建议使用初始化表。

23:

若不希望默认拷贝构造函数和赋值函数,则显式的声明一个空函数,设置为private。避免被人误使用。

24:

多考虑继承,组合的选择性。

25:

函数成员变量建议直到需要使用时再声明定义,建议函数成员变量定义时直接赋值为0或NULL,避免空声明。 注意有些函数内返回false时候,之前new的对象的delete。

26:

避免操作符按值返回结果。 例如: vector operator+( const vector& v1, const vector& v2 ) 使用起来是方便,但是要创建临时对象并复制,开销太大。 可使用 void operator+( const vector& v1, const vector& v2 ),由V1返回更好。虽然可读性低了,但是代价更低。当然,使用 += 不会出现这种情况,会比直接使用 + 更好。

27;

可能的话,避免 dynamic_cast 在开启RTTI的情况下,它才有意义,但是开销巨大。除非被严重继承的类对象使用时,可以考虑这种面向对象的设计方式。(很遗憾,某志还是懒的推荐它。)

28:

使用STL的时候,可能的话,使用vector替代set。 set维护的是一个红黑树,维护它的树结构时的代价经常比算法节省的时间代价大的多。