C++规范的整理---王海波
2010-11-16 11:34
113 查看
C++编程风格与规范 |
规则[/b](或建议) | 解释 |
1.排版
缩进[/b] | n程序块要采用缩进风格编写,缩进采用TAB键,长度统一为4个半角字符。 n对齐只使用TAB键,不使用空格键。 n函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。 |
最大长度、长行拆分[/b] | 较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。 例如: if ((very_longer_variable1>=very_longer_variable2) &&(very_longer_variable3<=very_longer_variable4) &&(very_longer_variable5<=very_longer_variable6)) { DoSomething(); } |
空行的使用[/b] | 相对独立的程序块之间必须加空行。 n在每个类声明之后、每个函数定义结束之后都要加2行空行。 n在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。 |
一行语句独占一行 | n一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。 n"if"、"for"、"while"、"do"、"try"、"catch"等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加"{}"。这样可以防止书写和修改代码时出现失误。 |
函数参数较长,进行划分[/b] | 对于参数比较多的函数,声明或者定义时注意把参数进行分行编写,适当时候预留空间给予注释。 |
空格的使用[/b] | n关键字之后要留空格。像"const"、"virtual"、"inline"、"case"等关键字之后至少要留一个空格,否则无法辨析关键字。像"if"、"for"、"while"、"catch"等关键字之后应留一个空格再跟左括号"(",以突出关键字。 n函数名之后不要留空格,紧跟左括号"(",以与关键字区别。 n"("向后紧跟。而")"、","、";"向前紧跟,紧跟处不留空格。 n","之后要留空格,如Function(x,y,z)。如果";"不是一行的结束符号,其后要留空格,如for(initialization;condition;update)。 n赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如"="、"+="">="、"<="、"+"、"*"、"%"、"&&"、"||"、"<<","^"等二元操作符的前后应当加空格。 n一元操作符如"!"、"~"、"++"、"--"、"&"(地址运算符)等前后不加空格。 n像"[]"、"."、"->"这类操作符前后不加空格。 n对于表达式比较长的for、do、while、switch语句和if语句,为了紧凑起见可以适当地去掉一些空格,如for(i=0;i<10;i++)和if((a<=b)&&(c<=d)) 例如: void Func1(intx,inty,intz);// 良好的风格 void Func1(intx,inty,intz);// 不良的风格 //=========================================================== if (year>=2000)// 良好的风格 if ( year >= 2000 ) // 不良的风格 if ((a>=b)&&(c<=d))// 良好的风格 if ( a >= b && c <= d ) // 不良的风格 //=========================================================== for (i=0;i<10;i++)// 良好的风格 for ( i = 0 ; i < 10 ; i ++) // 不良的风格 for (i=0;I<10;i++)// 过多的空格 //=========================================================== x =a<b?a:b;// 良好的风格 x = a < b ? a : b ; // 不好的风格 //=========================================================== int * x=&y;// 良好的风格 int *x=&y;// 不良的风格 //=========================================================== array [ 5 ] =0;// 不要写成 array[5]=0; a .Function(); // 不要写成 a.Function(); b ->Function(); // 不要写成 b->Function(); |
注释[/b] | n一般情况下,源程序有效注释量必须在20%以上。 n注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。将注释与其上面的代码用空行隔开。 n边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。 n注释应当准确、易懂,防止注释有二义性。错误的注释不但无益反而有害。避免在注释中使用缩写,特别是非常用缩写。 n当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。 n对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方。 n文件头部应进行注释,列出:版权说明、版本号、生成日期、作者、模块目的/功能、主要函数及其功能、修改日志等。 例如: //*!@file //********************************************************************* //<PRE> //模块名:<文件所属的模块名称> //文件名:<文件名> //相关文件:<与此文件相关的其它文件> //文件实现功能:<描述该文件实现的主要功能> //作者:<作者部门和姓名> //版本:<当前版本号> //-------------------------------------------------------------------- //多线程安全性:<是/否>[,说明] //异常时安全性:<是/否>[,说明] //-------------------------------------------------------------------- //备注:<其它说明> //--------------------------------------------------------------------- //修改记录: //日期版本修改人修改内容 //YYYY/MM/DDX.Y<作者或修改者名><修改内容> //</PRE> //********************************************************************** 附注:尽量避免使用/**/风格的注释,因为它不支持嵌套,容易引起问题。以上例中,每个“//”之后统一加入两个空格,为了美观。[/b] n函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等。 n数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方。 n全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明。 n对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。 |
2.命名规则
如果想要有效的管理一个稍微复杂一点的体系,针对其中事物的一套统一、带层次结构、清晰明了的命名准则就是必不可少而且非常好用的工具。在软件开发这一高度抽象而且十分复杂的活动中,命名规则的重要性更显得尤为突出。一套定义良好并且完整的、在整个项目中统一使用的命名规范将大大提升源代码的可读性和软件的可维护性。
在引入细节之前,先说明一下命名规范的整体原则:
同一性 | 在编写一个子模块或派生类的时候,要遵循其基类或整体模块的命名风格,保持命名风格在整个模块中的同一性。 |
标识符组成 | 标识符采用英文单词或其组合,应当直观且可以拼读,可望文知意,用词应当准确。 |
最小化长度&&最大化信息量原则 | 在保持一个标识符意思明确的同时,应当尽量缩短其长度。 |
避免过于相似 | 不要出现仅靠大小写区分的相似的标识符,例如“i”与“I”,“function”与“Function”等等。 |
避免在不同级别的作用域中重名 | 程序中不要出现名字完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但容易使人误解。 |
正确命名具有互斥意义的标识符 | 用正确的反义词组命名具有互斥意义的标识符,如:"nMinValue"和"nMaxValue","GetName()"和"SetName()".... |
避免名字中出现数字编号 | 尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。 |
函数
函数的命名[/b] | 函数的名称由一个或多个单词组成。为便于界定,每个单词的首字母要大写。 |
推荐的组成形式 | 函数名应当使用"动词"或者"动词+名词"(动宾词组)的形式。例如:"GetName()","SetValue()","Erase()","Reserve()".... |
保护成员函数[/b] | 保护成员函数的开头应当加上一个下划线“_”以示区别,例如:"_SetState()".... |
私有成员函数[/b] | 类似地,私有成员函数的开头应当加上两个下划线“__”,例如:"__DestroyImp()".... |
私有成员函数的层次结构表示 | 通常来说,在一个类中,公有方法、保护方法和私有方法所完成的任务总是呈现一种逐级依次细化的层次结构(意即:保护方法所实现的功能通常比该类中的公有方法更为细小琐碎;类似地,私有方法的功能也比其保护方法更具原子性)。 因此,对于遵循以上规则,并且功能较为复杂的类,在按照“公有、保护、私有”的三级形式划分以后,如果其私有成员中仍然存在明显不同的功能粒度,则可以通过追加更多下划线前缀的形式予以表示。 例如:由三个下划线开头的私有方法“___PushCdr”就要比同一类中,仅由两个下划线开头的私有方法“__MergeConCall”所完成的功能粒度更细小、更琐碎;而四个下划线开头的“____CalcCompensate”则比“___PushCdr”完成的功能更具原子性。 如果发现类中的功能层数太多(从公有方法到最“原子”的私有方法间,一般不应该超过7层),那通常反应一个不良的设计。此时请检查这个类的功能是否过于臃肿,已使接口显得不太清晰。另外一个常见的问题是将无需访问该类中私有或保护成员的功能定义成了方法。第一个问题可以通过重新划分类层次结构或将一个类分裂为多个类等方法解决。对于第二个问题,由于这些方法无需访问受限成员,大多数时候都可以把它们转变成局部函数(放在无名空间或使用“static”前缀定义)。 |
成员函数的下划线后缀命名 | 对一些本应该作为保护或私有成员的函数,由于设计方面的其它考虑(例如:灵活性、功能等方面)将其提升为公有成员的,应该在其后面添加与其原本访问控制级别相应的下划线后缀。 另外,对于其它不推荐直接使用的成员函数(例如:会引起兼容性或可移植性方面问题的函数),也应当在其后面加相应下划线提示。 例如:"ioctl_()","SetSysOpt_()","GetSysOpt_()","PreParser__()".... |
回调和事件处理函数 | 回调和事件处理函数习惯以单词“On”开头。例如:"_OnTimer()","OnExit()".... |
虚函数 | 回调函数以外的虚函数习惯以“Do”开头,如:"DoRefresh()","_DoEncryption()".... |
变量
变量应该是程序中使用最多的标识符了,变量的命名规范可能是一套C++命名准则中最重要的部分:变量的命名[/b] | n变量名由作用域前缀+类型前缀+一个或多个单词组成。为便于界定,每个单词的首字母要大写。 n对于某些用途简单明了的局部变量,也可以使用简化的方式,如:i,j,k,x,y,z.... n使用有意义的变量名。比如字符串拷贝函数:voidStringCopy(char*str1,char*str2);我们很难搞清楚究竟是把str1拷贝到str2中,还是刚好倒过来。可以把参数名字起得更有意义,如叫strSource和trDestination。这样从名字上就可以看出应该把strSource拷贝到strDestination。 n在保证名字有意义的前提下,使名字长度更加精炼。 | ||||||||||||||||||||||||
作用域前缀[/b] | 作用域前缀标明一个变量的可见范围。作用域可以有如下几种:
格外注意关于全局变量和局部静态变量的依赖性问题和初始化时的线程安全性问题。 | ||||||||||||||||||||||||
类型前缀[/b] | 类型前缀标明一个变量的类型,可以有如下几种:
| ||||||||||||||||||||||||
数值前缀的特别记法[/b] | 以“n”作为所有整形前缀是由于大多数情况下,编写程序时不需要过多考虑整形的宽度,但在某些场合中,整形宽度是需要特别注意并且仔细加以区分的,这时可使用如下记法代替“n”前缀:
| ||||||||||||||||||||||||
推荐的组成形式 | 变量的名字应当使用"名词"或者"形容词+名词"。例如:"nCode","m_nState","nMaxWidth".... |
常量
C++中引入了对常量的支持,常量的命名规则如下:常量的命名 | 常量名由类型前缀+全大写字母组成,单词间通过下划线来界定,如:cDELIMITER,nMAX_BUFFER.... 类型前缀的定义与 |
宏、枚举值
宏、枚举值的命名 | 宏和枚举值由全大写字母组成,单词间通过下划线来界定,如:ERROR_UNKNOWN,OP_STOP.... |
3.编程风格
基本风格
修饰符的位置[/b] | 为便于理解,应当将修饰符"*"和"&"紧靠数据类型。
| ||||
与常量的比较[/b] | 在与宏、常量进行"==","!=",">=","<="等比较运算时,应当将常量写在运算符左边,而变量写在运算符右边。这样可以避免因为偶然写错把比较运算变成了赋值运算的问题。
| ||||
运算符的优先级[/b][/b] | 如果代码行中的运算符比较多,应该用括号确定表达式的操作顺序,避免使用默认的优先级。因为熟记各运算符的优先级是比较困难的,就算你熟记并正确使用了,写出来的代码也容易产生歧义而使其可读性较差。 好的风格if((a|b)&&(a&c)) 坏的风格if(a|b&&a&c) 虽然后者和前者功能一样,但后者是很恐怖的,难以阅读。 | ||||
不要编写太复杂的复合表达式[/b] | 复合表达式使用在适当的场合可以使代码更加简洁,但不能因为这个简洁而带来理解的复杂。 例如: max=a>b?(a>c?a:c):(b>c?b:c)//复合表达式过于复杂 应该修改为:
| ||||
各种数据类型与零值比较[/b] | 在JAVA中,对于布尔变量flag,与零值(注意:不是0)比较的方式自然是if(flag==TRUE)或者if(flag==FALSE),但是在C/C++中这却不是正确的选择。 n正确的选择应该是if(flag)或者if(!flag),这是因为TRUE的值究竟是什么并没有统一的标准,例如VisualC++将TRUE定义为1,而VisualBasic则将TRUE定义为-1。if(flag==TRUE)、if(flag==1)、if(flag==FALSE)、if(flag==0)都属于不良风格。 n应当将整型变量用“==”或“!=”直接与0比较。if(value==0) if(value!=0) 不可以写成 if(value)//会让人误解value是布尔变量 if(!value) n指针变量的零值是NULL。尽管NULL的值与0相同,但是两者意义不同。对于指针变量p,它与零值比较的if语句如下: if(NULL==p) if(NULL!=p) 不要写成 if(0==p)//容易让人误解p是整型变量 if(0!=p) | ||||
避免嵌套过深[/b] | 不要出现这样的结构:
| ||||
乱指一气的指针[/b] | “野指针”者,乱指一气的指针也,它不是NULL指针,是指向“垃圾”内存的指针。野指针是很危险的,是经常导致bug的原因,它的成因主有两种:一是指针变量没有被初始化。在C/C++中任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。 二是指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。 | ||||
避免使用宏:[/b] 用内联函数代替宏函数、用const声明常量代替宏常量[/b] | 宏是C和C++中最生硬的工具,要避免使用宏。C++之父BjarneStroustrup说过,C++的目标之一就是使C的预处理器成为多余的,因为这天生就容易出错。 在C++中几乎不需要宏,可以用const或者enum定义易于理解的常量,用inline避免函数调用的开销,用template指定函数系列和类型系列,用namespace避免名称冲突。 关于宏的第一规则就是:不要使用它,除非不得不用。几乎每个宏都说明程序设计存在缺陷。 例外情况:[/b] 宏仍然是几个重要任务的唯一解决方案,比如#include保护符,条件编译中的#ifdef和#defined,以及assert的实现。 | ||||
总是初始化变量[/b] | 一切从白纸开始,未初始化的变量时C和C++中错误的常见来源。养成在使用内存之前先清除的习惯,可以避免这种错误,在定义变量的时候就将其初始化。 使用过程式的语言(如Pascal、C、Fortran或Cobol)的人,可能有这样的习惯:独立于使用它们的代码来定义变量,然后再要使用的时候赋值。这种方法已经过时了,是不可取的。 | ||||
避免函数过长[/b] | 短胜于长,平优于深:过长的函数和嵌套过深的代码块的出现,经常是因为没能赋予一个函数以紧凑的职责所致,这两种情况通常能够通过重构予以解决。 函数试图将多个这样的小概念单元合并到一个长的函数体中,那么它最终将不堪重负。建议如下: l尽量紧凑:对一个函数只赋予一种职责。 l不要自我重复:优先使用命名函数,而不要让相似代码片段反复出现。 l优先使用&&:在可以使用&&条件判断的地方要避免使用连续嵌套的if。 l不要过分使用try:优先使用析构函数进行自动清除而避免使用try代码块。 l优先使用标准算法:算法比循环嵌套要少,通常也更好。 l不要根据类型标签(typetag)来进行分支(switch),优先使用多态函数。 | ||||
尽量减少定义性依赖。避免循环依赖[/b] | 不要过分依赖:如果用前向声明(forwarddeclaration)能够实现,那么不要包含(#include)定义。 不要互相依赖:循环依赖是指两个模块之间或间接地互相依赖。所谓模块是指紧凑的发布单元(如一个.cpp和同名.h就是一个单元),互相依赖的多个模块并不是真正的独立模块,而是紧凑的更大模块,因此循环依赖有碍于模块性,是大型项目的祸根。请避免循环依赖。 一般而言,应该在模块层次上考虑依赖性及其循环。模块是一同发布的类和函数的紧凑几何。最简单形式的循环依赖是两个互相依赖的类:
如果依赖循环跨越多个模块的话,情况会变得很糟糕,因为必须联合这些模块组成更大的单元再进行发布。 为了打破循环,可以应用面向对象中的优秀思想原则:依赖倒置原则:不要让高层模块依赖于底层模块;相反,应该让两者都依赖于抽象。[/b]如果能够为Parent和Child定于独立的抽象类,那么就能打破循环了。多数设计模式都是本着依赖倒置原则的设计理念进行面向对象设计的。 | ||||
尽量使用初始化而不是在构造函数里赋值[/b] | 对象创建分为两步: 1.数据成员初始化; 2.执行被调用构造函数体内的动作。 (对于有基类的对象来说,基类的成员初始化和构造函数体内的执行发生在派生类的成员初始化和构造函数的执行之前)。这就经常意味着对象的成员在执行到构造函数体内之前已经被构造了,然后再构造函数体内又进行了一次赋值操作。这样每个对象成员都进行了调用:一次是缺省构造函数,另一次是赋值。当对象成员较多或其成员本身比较“大”时,导致了严重效率浪费。 例外情况: 1.当有大量的固定类型的数据成员要在每个构造函数里以相同的方式初始化的时候,对类的数据成员赋值比用初始化更合理。
|
类/结构风格
类是C++中最重要也是使用频率最高的新特性之一,类的版式好坏将极大地影响代码品质。注释头与类声明[/b] | 与文件一样,每个类应当有一个注释头用来说明该类的各个方面。 类声明换行紧跟在注释头后面,"class"关键字由行首开始书写,后跟类名称。界定符"{"和"};"应独占一行,并与"class"关键字左对齐。
| ||
继承[/b] | 基类直接跟在类名称之后,不换行,访问说明符(public,private,或protected)不可省略。如:
| ||
以行为为中心[/b] | 没人喜欢上来就看到一大堆私有数据,大多数用户关心的是类的接口与其提供的服务,而不是其实现。 所以应当将公有的定义和成员放在类声明的最前面,保护的放在中间,而私有的摆在最后。 | ||
访问说明符[/b] | 访问说明符(public,private,或protected)应该独占一行,并与类声明中的‘class’关键字左对齐。 | ||
类成员的声明版式[/b] | 对于比较复杂(成员多于20个)的类,其成员必须分类声明。 每类成员的声明由访问说明符(public,private,或protected)+全行注释开始。注释不满全行(80个半角字符)的,由"/"字符补齐,最后一个"/"字符与注释间要留一个半角空格符。 如果一类声明中有很多组功能不同的成员,还应该用 每个成员的声明都应该由"class"关键字开始向右缩进一个制表符(4个半角空格符),成员之间左对齐。 例如:
| ||
正确地使用const和mutable | 把不改变对象逻辑状态的成员都标记为const成员不仅有利于用户对成员的理解,更可以最大化对象使用方式的灵活性及合理性(比如通过const指针或const引用的形式传递一个对象)。 如果某个属性的改变并不影响该对象逻辑上的状态,而且这个属性需要在const方法中被改变,则该属性应该标记为"mutable"。 例如:
| ||
嵌套的类声明 | 在相应的逻辑关系确实存在时,类声明可以嵌套。嵌套类可以使用简单的单行注释头:
| ||
初始化列表 | 应当尽可能通过构造函数的初始化列表来初始化成员和基类。初始化列表至少独占一行,并且与构造函数的定义保持一个制表符(4个半角空格)的缩进。 例如:
如果一个成员"a"需要使用另一个成员"b"来初始化,则"b"必须在"a"之前声明,否则将会产生运行时错误(有些编译器会给出警告)。 例如:
|
函数
函数原型 | 函数原型的格式为:
以"[]"括住的为可选项目。 除了构造/析构函数及类型转换操作符外,"返回值类型"和"参数列表"项不可省略(可以为"void")。 "const说明符"仅用于成员函数中。 "存储类","参数列表"和"异常过滤器"的说明见下文。 | ||||||||||||||||||||||||
函数声明 | 函数声明的格式为:
声明类的成员函数时,为了紧凑,返回值类型和函数名之间不用换行,也可以适当减少声明间的空行。 | ||||||||||||||||||||||||
函数定义 | 函数定义使用如下格式:
| ||||||||||||||||||||||||
参数描述宏 | 以下预定义宏对程序的编译没有任何影响,只为了增强对参数的理解:
除了空参数"void"和哑元参数以外,每个参数左侧都必须有"IN"和/或"OUT"修饰。 既输入又输出的参数应记为:"INOUT",而不是"OUTIN"。 IN/OUT的左侧还可以根据需要加入一个或多个上表中列出的其它宏。 参数描述宏的使用思想是:只要一个描述宏可以用在指定参数上(即:对这个参数来说,用这个描述宏修饰它是贴切的),那么就应当使用它。 也就是说,应该把能用的描述宏都用上,以期尽量具体地描述一个参数的作用和用法等信息。 | ||||||||||||||||||||||||
参数列表 | 参数列表的格式为:
| ||||||||||||||||||||||||
存储类 | "extern","static","inline"等函数存储类说明应该在声明和定义中一致并且显式地使用。不允许隐式地使用一个类型声明,也不允许一个类型声明仅存在于函数的声明或定义中。 | ||||||||||||||||||||||||
成员函数的存储类 | 由于C++语言的限制,类中成员函数的"static","virtual","explicit"等存储类说明不允许出现在函数定义中。 但是为了明确起见,这些存储类应以注释的形式在相应的成员定义中给出。 例如:
| ||||||||||||||||||||||||
默认参数 | 类似地,参数的默认值只能出现在函数声明中,但是为了明确起见,这些默认值应以注释的形式在定义中给出。 例如:
| ||||||||||||||||||||||||
异常过滤器 | 对于任何可能抛出异常的函数,必须在其声明和定义中显式地指定异常过滤器,并在过滤器中列举该函数可能抛出的异常。 例如:
特别地:如果一个函数内部显式地捕获了任何可能的异常(例如:使用了"catch(...)"),并且保证不抛出任何异常,那么应该在其声明和定义中显式地指定一个空异常过滤器:"throw()"。 例如:
| ||||||||||||||||||||||||
代码段注释 | 如果函数体中的代码较长,应该根据功能不同将其分段。代码段间以空行分离,并且每段代码都以 例如:
| ||||||||||||||||||||||||
调用系统API[/b] | 所有系统API调用前都要加上全局名称解析符"::"。 例如:
| ||||||||||||||||||||||||
让相同的代码只出现一次[/b][/b] | 为了使程序更容易调试、修改,尽量降低日后维护的复杂性,应该把需要在一个以上位置使用的代码段封装成函数。哪怕这段代码很短,为了以后维护方便着想,也应当将其封装为内联函数。 | ||||||||||||||||||||||||
函数版式实例[/b] | /*!@function ******************************************************************************** <PRE> 函数名:GetAllSubDirs 功能:获得所有符合条件的子目录列表 参数:[OUT]vResult:用来储存结果 [IN]dirPattern:要查找的子目录通配符 [IN]includeSubdir:是否包含子目录 [IN]includeHidden:是否包含隐含目录 [IN]includeDot:是否包含“.”和“..”系统目录 返回值:符合条件的子目录数量 抛出异常:- -------------------------------------------------------------------------------- 备注:无论是否成功,vResult中的原内容都将被清空 典型用法:- -------------------------------------------------------------------------------- 作者: </PRE> *******************************************************************************/ ULONG CDir::GetAllSubDirs(OUTVSTR&vResult, INtstringExdirPattern/*=byT("*")*/, INboolincludeSubdir/*=false*/, INboolincludeHidden/*=true*/, INboolincludeDot/*=false*/)const { //========================================================================= //=初始化 vResult.clear(); if(dirPattern.empty()||!IsValid()) { return0; } WIN32_FIND_DATAFindFileData; HANDLEhFind; tstringExPattern=m_basedir+DELIMITER+dirPattern; //========================================================================= //=匹配子目录 hFind=::FindFirstFile(Pattern.c_str(),&FindFileData); if(INVALID_HANDLE_VALUE==hFind) { return0; } intn; tstringExstDir; if(-1!=(n=dirPattern.find_last_of(ALLDELIMITERS))) { stDir=m_basedir+DELIMITER+dirPattern.substr(0,n)+DELIMITER; } else { stDir=m_basedir+DELIMITER; } do { if(!(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)) { gotofindnext; } if(IsDotDir(FindFileData.cFileName)&&!includeDot) { gotofindnext; } if((FindFileData.dwFileAttributes&FILE_ATTRIBUTE_HIDDEN) &&!includeHidden) { gotofindnext; } //递归搜索子目录 if(includeSubdir&&!IsDotDir(FindFileData.cFileName)) { VSTRrr; tstringExrdir; if(-1!=n) { rdir=dirPattern.substr(0,n)+DELIMITER+FindFileData.cFileName +DELIMITER+dirPattern.substr(n+1,-1); } else { rdir=FindFileData.cFileName+DELIMITER+dirPattern; } GetAllSubDirs(rr,rdir,includeSubdir,includeHidden,includeDot); constULONGcount=rr.size(); for(ULONGi=0;i<count;++i) { vResult.push_back(rr[i]); } }//if(includeSubdir&&!IsDotDir(FindFileData.cFileName)) vResult.push_back(stDir+FindFileData.cFileName); findnext: if(!::FindNextFile(hFind,&FindFileData)) { break; } }while(true); ::FindClose(hFind); returnvResult.size(); } |
变量、常量
声明格式[/b] | 变量、常量的声明格式如下:
以"[]"括住的为可选项目。 "存储类"的说明见下文 | ||||||||
定义格式[/b] | 变量、常量的定义格式如下:
以"[]"括住的为可选项目。 "存储类"的说明见下文 | ||||||||
存储类[/b] | 除"auto"类型以外,诸如"extern","static","register","volatile"等存储类均不可省略,且必须在声明和定义中一致地使用(即:不允许仅在声明或定义中使用)。 | ||||||||
成员变量的存储类[/b] | 由于C++语言的限制,成员变量的"static"等存储类说明不允许出现在变量定义中。但是为了明确起见,这些存储类应以注释的形式在定义中给出。例如:
| ||||||||
指针或引用类型的定义和声明[/b] | 在声明和定义多个指针或引用变量/常量时,每个变量至少占一行。例如:
| ||||||||
常指针和指针常量[/b] | 声明/定义一个常指针(指向常量的指针)时,"const"关键字一律放在类型说明的左侧。 声明/定义一个指针常量(指针本身不能改变)时,"const"关键字一律放在变量左侧、类型右侧。例如:
| ||||||||
全局变量、常量的注释[/b] | 全局变量、常量的注释独占一行,并用"//!"开头。例如:
| ||||||||
类型转换[/b] | 禁止使用C风格的"(类型)"类型转换,应当优先使用C++的"xxx_cast"风格的类型转换。C++风格的类型转换可以提供丰富的含义和功能,以及更好的类型检查机制,这对代码的阅读、修改、除错和移植有很大的帮助。其中:
通常来说,"xxx_cast"格式的转换与构造函数风格的类型转换之间,最大的区别在于:构造函数风格的转换经常会生成新的临时对象,可能伴随相当的时间和空间开销。而"xxx_cast"格式的转换只是告诉编译器,将指定内存中的数据当作另一种类型的数据看待,这些操作一般在编译时完成,不会对程序的运行产生额外开销。当然,"dynamic_cast"和某些"static_cast"则例外。 |
4.版本控制
n源代码的版本按文件的粒度进行维护。n创建一个新文件时,其初始版本为"1.0",创建过程中的任何修改都不需要增加修改记录。
n从软件第一次正式发布开始,对其源文件的每次修改都应该在文件头中加入相应的修改记录,并将文件的子版本加1。
n升级软件的主版本时,其源文件的相应主版本号随之增加。与创建新文件时一样,在该主版本第一次发布之前,对文件的任何修改都不需要再增加修改记录。
修改标记
|
5.常用英文注释
文件头注释
/*!@file ******************************************************************************** <PRE> Module: File: RelatedFiles: Intro: Author:<xxx> Version:1.0 -------------------------------------------------------------------------------- MutiThreadSafety: OnExceptionSafety: -------------------------------------------------------------------------------- Notes: -------------------------------------------------------------------------------- ChangeHistory: DateVersionChangedByChanges YYYY/MM/DD1.0<xxx>Create </PRE> ******************************************************************************** *Copyright(c)YYYY,by<xxx>,Allrightsreserved *******************************************************************************/ |
标准类注释
以下定义的各种成员类型可以根据实际需要增删。/*!@class ******************************************************************************** <PRE> Class: Desc: Exception: -------------------------------------------------------------------------------- Notes: Examples: -------------------------------------------------------------------------------- Author:<xxx> </PRE> *******************************************************************************/ classCXXX { public: ////////////////////////////////////////////////////////////////////////defines public: //////////////////////////////////////////////////////////////////////bigthree public: //////////////////////////////////////////////////////////////////virtualfuncs public: ///////////////////////////////////////////////////////////////////publicfuncs public: ///////////////////////////////////////////////////////////////////staticfuncs protected: /////////////////////////////////////////////////////////////////internalfuncs private: ////////////////////////////////////////////////////////////////privatedefines private: //////////////////////////////////////////////////////////////////privatefuncs private: /////////////////////////////////////////////////////////////////////properties private: //////////////////////////////////////////////////////////////staticproperties private: ////////////////////////////////////////////////////////////////disabledmethod }; |
标准函数注解
/*!@function ******************************************************************************** <PRE> Function: Desc: Params: Return: Exception: -------------------------------------------------------------------------------- Complexity: Notes: Examples: -------------------------------------------------------------------------------- Author:<xxx> </PRE> *******************************************************************************/ |
语句/函数组//[[GroupTitle... //]][GroupTitle] OR //----[[GroupTitle ... //----]][GroupTitle] |
相关文章推荐
- C++代码注释规范(整理)
- C++代码注释规范(整理)
- C++常见用法规范整理
- [C++]项目中的代码注释规范(整理)
- C++规范的整理
- c++第二周任务三#(3-2)整理规范的文本
- [C++]项目中的代码注释规范(整理)
- 提高项目31.4-读入一个C++程序,整理其格式,使其按规范排版
- c++命名规范
- 找工作C++面试资料之问答题整理(1)
- 第八章 Android开发规范整理以及Strings.xml定义规范化
- c++零碎知识整理
- 转:推荐!国外程序员整理的 C++ 资源大全
- 前端 CSS 规范整理
- 国外程序员整理的 C++ 资源大全
- c++ 关于字符串处理函数的整理
- C++菜鸟常见错误整理(第四天)
- 国外程序员整理的 C++ 资源大全
- 【干货】国外程序员整理的 C++ 资源大全
- c++命名规范与代码风格