软件编码规范_第1页
软件编码规范_第2页
软件编码规范_第3页
软件编码规范_第4页
软件编码规范_第5页
已阅读5页,还剩49页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、编号:V V C C 软软 件件 编编 码码 规规 范范目 次1 范围范围.11.1 目的.11.2 使用范围.12 术语术语.12.1 软件项目.12.2 宏定义.12.3 方法.12.4 函数.12.5 操作.12.6 属性.12.7 MFC .13 基本约定基本约定.23.1 工程风格.23.1.1 工程命名.23.1.2 工程目录设置.23.1.3 集成环境内的工程目录设置.23.1.4 工程修改记录追踪.33.2 文件风格.33.2.1 文件生成.33.2.2 文件头部注释.43.2.3 空行约定.63.2.4 格式约定.73.3 函数风格.103.3.1 函数注释.103.3.2

2、代码缩进.143.3.3 函数命名.153.3.4 函数要求.153.3.5 语句要求.163.4 变量风格.203.4.1 变量定义的位置.203.4.2 变量命名规则.203.4.3 变量初始化要求.253.4.4 全局变量.253.5 注释风格.263.5.1 注释格式.263.5.2 必须注释的部分.264 类的约定类的约定.274.1 类的描述.274.2 类风格.284.2.1 类要求.284.3 类的声明.334.4 类的实现.344.4.1 成员函数的参数.344.4.2 成员函数的注释.355 其他约定其他约定.375.1 其他命名约定.375.1.1 结构体名.375.1.

3、2 共同体(又称联合体)名.385.1.3 枚举类型名.395.2 异常处理.405.3 其他编码规则.41附表附表 A 基于基础类的类名、类对象的前、后缀定义基于基础类的类名、类对象的前、后缀定义.4311范围1.1目的随着越来越多的软件系统需要 Visual C+(以下简称 VC)来编写,为了便于各位系统负责人、软件设计人员、程序员、测试人员间交流软件系统源程序,并且保证源程序的可读性、可维护性、可测性,特制定本文档。1.2使用范围本文档只规定基于 VC 设计的软件编程规范,主要针对 Windows 平台。本文档的读者为系统负责人、软件设计人员、程序员、测试人员,以期在编码过程之中,保持一

4、致的风格,有利于软件工程项目的推行。2术语2.1软件项目一项需要协同工作的任务,它关注系统中软件成分的分析、说明、设计、开发、测试和(或)维护等工作及其相关文档。一个软件项目可以是建造硬件/软件系统的项目的一部分。2.2宏定义VC 提供的一种预处理功能,又称宏代换、宏替换。2.3方法类的操作函数。2.4函数将一段经常需要使用的代码封装起来,在需要使用时可以直接调用。2.5操作对象封装数据(表示为属性集合)和处理数据的算法。定义对象的行为并以某种方式修改对象的属性。2.6属性描述类的数据抽象。属性依附于类和对象,并以某种方式描述类或对象。2.7MFCMFC 是微软生成的名为微软基础类(Micro

5、soft Foundation Classes)的 C+类集的英文缩写。23基本约定每位程序员都有自己的编程风格,因为每位程序员都有自己的学习过程,就象每个人的个性一样,所以编程风格是风采各异、百花齐放;而从软件工程理论、实践来看,现代软件是多人合作的结晶,编程风格是否统一,直接关系到软件的可读性、可维护性、可测性以及培训的难易程度,继而对软件开发成本有着直接的关系,编程风格一致,软件项目易培训,其它人员接手老项目的时间缩短,便于程序员之间的交流。编程风格混乱,则其它人员接手老项目时间增长,同时随着项目的不断开发,项目或者单个源程序文件内有着多种编程风格,这样不利于整个项目的开展以及程序员之间

6、的交流。本章节描述了一个基于 VC 编译器的项目风格,力求一种统一的编程风格,并从工程风格、代码文件风格、函数编写风格、变量风格、注释风格几个方面进行阐述。3.1工程风格工程风格指的是针对整个工程,包括工程目录设置、相关库文件设置、Visual Studio 集成环境设置等等的习惯约定。具体有如下约定:工程命名、工程目录设置、集成环境内的工程目录设置、工程修改记录追踪。3.1.1工程命名在 VC 之中,工程名为最后可执行文件名,所以工程名与最终的可执行文件名一致。【强制】3.1.2工程目录设置为保证 VC 工程的备份方便、快捷,可将所有该工程有关的文件全部放到统一的目录之下,为每个工程在该目录

7、之下建立一个目录。a) 在工程目录下建立Include目录,存放工程引用的所有.h文件;【强制】b) 在工程目录下建立Lib目录,存放工程使用的所有.lib文件;【强制】c) 在工程目录下建立Img目录,存放工程使用的所有图标、图片文件;【推荐】d) 在工程目录下建立Bin目录,存放工程使用的所有可执行程序及相关运行环境。【强制】3.1.3集成环境内的工程目录设置3每个工程在 VC 编辑环境的设置都采用相对路径的设置,不可采用绝对路径,保证其从备份的光盘设备中恢复到硬盘时,不需要再过多的设置就可直接编译。同样在用#include 语句时不要使用工程目录以外的路径。【强制】如果引用的头文件在工程

8、目录下(在 include 目录下),#include 可以包含相对路径;#include “./include/somehead.h”如果引用的头文件不在工程目录下,必须在项目设置中加入该头文件的所在目录。#include “somehead.h”3.1.4工程修改记录追踪每一个 VC 工程必须存在 Changes.Log,用以记载工程产生以来所有的改动。【推荐】日期: 2010/4/28修改人: 程旷修改主题: 底层通讯由于 MODEM 响应代码而引起的不稳定现象相关修改文件: CommLayer.cpp修改内容详细描述:3.2文件风格3.2.1文件生成a)对于规范的VC派生类,应使用开发

9、工具提供的功能(如VC6中的Class Wizard)生成文件格式,避免用手工制作的头文件/实现文件。【强制】b)在一个头文件(以.h为后缀的文件)中,只应该包含对一个类的声明(嵌套类的情况除外)。【推荐】c)在头文件中只包含声明,不要包含全局变量和函数的定义(内联函数的情况除外)。【强制】d)在一个实现文件(以.cpp为后缀的文件)中定义的每一个函数,都应该属于同一个类,即对一个类的实现描述要独占一个文件。【推荐】e)在实现文件中只应该包含对类的实现,不应该包含任何类的声明。类声明应该统一放到头文件中。【强制】f)只允许头文件被包含到其它的代码文件中去。【强制】4g)头文件中应该有避免重复包

10、含的预处理。【强制】头文件的格式应该类似于:#ifndef #define .#endif /或者:#if !defined ()#define .#endif /h)代码文件的名字要与文件中声明、定义的类的名字基本保持一致,使类名与类文件名建立联系。【推荐】将类 CMsgDialog 的头文件和实现文件命名为 msgdialog.h 和 msgdialog.cpp。3.2.2文件头部注释a) 头文件由三部分组成:头文件开头处的版权声明、预处理块、函数和类结构声明等。【强制】/ 版权声明/* Copyright (c) 2010,某某单位 * All rights reserved.* * 文

11、件名称:graphics.h* 摘 要:简要描述本文件的内容* * 创建者: * 创建时间:2010/4/28*/5#ifndef GRAPHICS_H/ 防止 graphics.h 被重复引用#define GRAPHICS_H#include / 引用标准库的头文件#include myheader.h/ 引用非标准库的头文件class Box / 类结构声明;#endifb) 实现文件由三部分组成:实现文件开头处的版权声明和编写与修改记录、对一些头文件的引用、程序的实现体(包括数据和代码)。【强制】例如:/ 版权声明/* Copyright (c) 2001,某某单位* All righ

12、ts reserved.* * 文件名称:graphics.cpp* 摘 要:简要描述本文件的内容* 编写与修改记录:* * 张三 2010.05.09 0.1 初版* 张三 2011.06.10 0.4 修改信息收发部分* 李四 2012.01.01 1.1 增加了信息处理处求算术平均值的功能*/ 引用头文件#include graphics.h 6/ 类成员函数的实现体void Box:Draw()3.2.3空行约定文件之中不得存在无规则的空行,不能出现连续三个以上空行;在头文件和实现文件中,各主要部分(包括:序言性注释、防止被重复包含部分(只在头文件中)、#include 部分、#def

13、ine 部分、类型声明和定义部分、实现部分等)之间要用空行隔开,宜用 12 行空行。【强制】/ 版权和版本声明/* Copyright (c) 2010,某某单位* All rights reserved.* 文件名称:graphics.h* 摘 要:简要描述本文件的内容*/#ifndef GRAPHICS_H / 防止 graphics.h 被重复引用#define GRAPHICS_H#include / 引用标准库的头文件#include myheader.h / 引用非标准库的头文件class Box / 类结构声明;#endif7一般来讲函数与函数之前的空行为 2-3 行,在函数体内

14、部,在逻辑上独立的两个函数块可适当空行,一般为 1-2 行。【强制】void Function3()while (condition)statement1;if (condition)statement2;elsestatement3;statement4;3.2.4格式约定a)在使用赋值运算符、逻辑运算符、位运算符、算术运算符等二元操作符时,在其两边各加一个空格。【强制】nCount = 2;b)函数的各参数间要用“,”和一个空格隔开。【强制】void GetDate(int x, int y); c)不要在引用操作符前后使用空格,引用操作符指“.”和“-”,以及“”。【强制】不要这样写:m

15、_pFont - CreateFont();8应该这样写:m_pFont-CreateFont();d)不要在“:”前后使用空格。【强制】namespace N void globalFoo1();void globalFoo1() void globalFoo2() /不要这样写:: globalFoo1();: N : globalFoo1();/应该这样写::globalFoo1();:N:globalFoo1();e)不要在一元操作符和其操作对象之间使用空格,一元操作符包括“+”、“-”“!”、“&”、“*”等。【强制】不要这样写:i +;应该这样写:i+;f)对程序语句要按其

16、逻辑进行水平缩进,以四个空格或一个Tab符为单位(推荐使用Tab符),使同一逻辑层次上的代码在列上对齐。【强制】if(0 != nCount)for(i = 0; i min) x-;i)一行只写一条程序语句。【强制】x = x0;y = y0;while(true = IsOk(x) 10 x+;j)一次只声明、定义一个变量。【推荐】不要这样写:int iParam1, iParam2;应该这样写:int iParam1 = 0;int iParam2 = 0;k)对指针变量、引用变量的声明、定义,一次只声明、定义一个变量。【强制】不要这样写:int *pSum1,*pSum2;应该这样写:

17、int *pSum1 = NULL;int *pSum2 = NULL;l)在函数或类的成员函数体内定义变量时,同时要为变量赋初值。【强制】int fun1()int iTemp = 0;int i = 0;int j = 0;return iTemp;m)对于一个复杂的表达式,在一个二元、三元操作符操作的操作数的两边,应该放置“(”和“)”。【推荐】result = (fact / 100) * number) + rem;n)全局函数被调用时应加“:”标志。强制11void Print(); / 全局函数class Avoid Print(); / 成员函数不论两个Print 函数的参数是

18、否不同,如果类的某个成员函数要调用全局函数Print,为了与成员函数Print区别,全局函数被调用时应加“:”标志。当然,不建议全局函数与成员函数同名。:Print(); / 表示Print 是全局函数而非成员函数3.3函数风格3.3.1函数注释a) 使用开发工具提供的功能(如VC6中的Class Wizard)自动生成的函数,如消息响应函数,则不必太多的注释和解释;对于自行编写的函数,若是系统关键函数,则必须在函数实现部分的上方标明该函数的信息。【推荐】b) 函数的注释主要目的是说明本函数的功能、输入、输出参数和返回值等。在注释中可以详细描述本函数实现关键技术,另外,函数的注释也可以包含作者

19、等。其中,“参数”节包含4个部分,分别是:类型说明、含义、输入/输出、取值范围和有效性。“输入/输出”可能的取值是:I、O、I/O,分别表示参数是输入、输出和输入输出的。“返回值”包含两个部分:类型说明和返回值含义。【强制】/*函数名:unsignedToStr(unsigned u, char* str, unsigned base)功能描述:把无符号数转换成文本数字参数:unsigned u:被转换的无符号数I无符号整数 char* str:结果字符串O字符串 unsigned base:进制I0 或 16全局变量:无返回值: int 0:输入正确,输出字符串有效 1:被转换的无符号数输入

20、无效,输出字符串无效 2:进制输入无效,输出字符串无效*/12c) 在所有的条件编译或条件包含等预处理中,开始的#if语句和结束的#endif语句应该有对应的注释,表明#if语句的开始和结束。【强制】/ 检测 SYSTEM 的值,决定应包含哪个头文件,以对应不同的操作系统#if SYSTEM = SYSV /* SYSTEM */#define HDR sysv.h#elif SYSTEM = BSD #define HDR bsd.h#elif SYSTEM = MSDOS #define HDR msdos.h#else #define HDR default.h#endif /* SYS

21、TEM */#include HDRd) 对每个空循环体给出确认性注释。【推荐】int i;for( i = 0; i nameind应该这样写:#define GET_NAME(obj,ind) (obj)-name(ind)3.3.5语句要求a) 在一条程序语句中,只应包含一个赋值操作符。赋值操作符包括:=, +=, -=, *=, /=, %=, =, = -EPSINON) & (fLength = EPSINON) / EPSINON 是允许的误差(即精度)i) 在switch语句中,每一个case分支都要以break作为分支的结尾(几个连续的空case语句允许共用一个),一

22、定要有default分支来处理其它情况。【强制】switch(nNumber)case 1: nCount+; break;case 2: case 3: / 当 nNumber 等于 2 或 3 时,进行同样的处理nCount-; break; default: break;20j) 在定义指针变量的同时,对其进行初始化。如果定义时还不能为指针变量赋予有效值,则使其指向NULL。【强制】不要这样写:int* pNum;pNum = &iNum;应该这样写:int* pNum = &iNum;k) 当指针变量所指的内存被释放后,应该赋予指针NULL值。【强制】char *p =

23、 (char *) malloc(100);strcpy(p, “hello”);free(p); / p 所指的内存被释放,但是 p 所指的地址仍然不变if(NULL != p) / 没有起到防错作用strcpy(p, “world”); / 出错/应该这样写char *p = (char *) malloc(100);strcpy(p, “hello”);free(p);p = NULL;3.4变量风格3.4.1变量定义的位置定义变量有四个基本的位置:在函数的内部、在函数的定义中、在所有函数的外部以及在定义类的内部。这些变量分别称为局部变量、形式参数、全局变量和类成员变量。3.4.2变量命

24、名规则21变量尽量采用 VC 中的原则;一般情况下,变量的取名方式为:【强制】也可描述为:命名要求如下:a) 在程序中声明、定义的变量、常量、宏、自定义类型、函数,在对其命名时应该使用有意义的名字,做到见其名知其意。【强制】/ 宏定义#define MAX_LINE_NUM 20/ 常量定义const float maxLineNum = 20;b) 一般变量由3部分组成,即作用域(变量范围因子)、前缀(变量类型因子)和描述词(变量属性因子)。在变量范围因子的后面加下划线,变量类型因子与变量属性因子连在一起;【强制】int m_iLoop;其中,m为作用域(变量范围因子),表示此变量为类成员变

25、量;i为前缀(变量类型因子),表示此变量为int 型数据;Loop为描述词(变量属性因子),表示此变量为用于循环控制的变量。c) 变量、声明、自定义类型、函数名中含多于一个单词时,每个单词的第一个字母大写。【强制】int m_iRadioStation;/ 无线电台数量d) 宏、常量的名字要全部大写,多个单词用下划线分开。【强制】const int NUMBER = 100;/ const 修饰的量enum ONE, TWO, THREE ;/ 枚举量#define MAX_INT 99/ 宏22e) 自定义类型名应以大写字母打头,自定义类型包括:class、struct、enum、union

26、、typedef声明的类型、namespace。【推荐】typedef struct Student;f) 标识符名字长度应在一个恰当的范围内,名字太长不够简洁,名字太短又不能清晰表达含义。在程序中声明、定义的变量、常量、宏、类型、函数,它们的名字长度要在3至25个字符之内(下限不包括前缀,上限包括名字中所有的字符);对于某些已经被普遍认同的简单命名,可不受本规则的限制。如for循环的循环记数变量,可使用i、j等简单字符命名。【强制】const int NUMBER = 100;/ const 修饰的量enum ONE, TWO, THREE ;/ 枚举量#define MAX_INT 99/

27、 宏3.4.2.1作用域(变量范围因子)作用域(变量范围因子),g 表示此变量为全局变量,在各个函数内使用;m 表示此变量为类或结构内的成员变量,在类内或结构内有效;若无变量范围因子,则表示此变量作为函数参数传入或者函数内局部变量。【强制】变量作用域风格见表 3-1。表 3-1 变量作用域风格前缀类型例子g_Global(全局)Variable g_ServersCClassor structure(类或结构)CDocument, CPrintInfom_Member variable(成员变量)m_pDoc, m_nCustomers3.4.2.2前缀(变量类型因子)前缀(变量类型因子)根据

28、变量的类型而变化,由于变量的类型较多,在使用没有被讨论到的类型(尤其是声明某些类的对象)时可以灵活掌握,但要掌握的原则是:1)要明确此变量的类型,不要和其他类型相混淆;2)在满足第一条原则的情况下,前缀(变量类型因子)不要太长,尽量不要超过 4 个字母。【强制】char chName;BOOL bEnabled;int iLength;23VC 常用的前缀见表 3-2。表 3-2 VC 常用前缀表前缀类型描述例子chchar8-bit characterchGradeuchunsigned charuchGradechTCHAR16-bit character if _UNICODE is d

29、efinedchNamebBOOLBoolean valuessbEnabledbyBYTEAn 8-bit integer that is not signedbyInstructionshshortshort intshNunberiintInteger (size dependent on operating system)iLengthnUINTUnsigned valuess (size dependent on operating system)nLengthffloatfloatfPaiddoubledoubledDistancewWORD16-bit unsigned valu

30、esswPoslLONG32-bit signed integerlOffsetdwDWORD32-bit unsigned integerdwRangep*Ambient memory model pointerpDoclpFAR*Far pointerlpDoclpszLPSTR32-bit pointer to character stringlpszNamelpszLPCSTR32-bit pointer to constant character stringlpszNamelpszLPCTSTR32-bit pointer to constant character string

31、if _UNICODE is definedlpszNamehhandleHandle to Windows objecthWndlpfn(*fn)()callbackFar pointer to CALLBACK functionlpfnAbortp+*int* piu+unsigned+Unsigned short ush3.4.2.3描述词(变量属性因子)描述词(变量属性因子)表示本变量所代表的现实含义,在对变量进行命名的时候,优先使用名词,在名词无法明确表达含义时,使用“动词+名词”进行表达。变量名称首先要表达所代表的含义,不要被变量名称长度等因素限制。单词有简写形式时,推荐使用简写形

32、式。【推荐】int iLength;double dWaitTime;常见单词的简写形式见表 3-3。【推荐】24表 3-3 常见单词的简写形式缩写对应单词cntcount个数descdescription描述dftdefault缺省evtevent事件fn, , funcfunction函数if, intfinterface接口infoinformation信息intrinterrupt断itvlinterval间隔lenlength长度lvllevel级别memmemory内存,存储mgmt, , mgmanagement管理mgmtapp, ,mgappmanagement applic

33、ation管理应用mgrmanager管理者modumodule模块msgmessage消息numnumber编号ptrpointer指针rcvreceive接收rcvrreceiver接收器refreference引用reqrequest请求resresult结果respresponse响应retreturn返回rtnroutine例程secsection段sndsend发送spdspeed速度svrserver服务器syncsynchronous同步thrdthread线程25缩写对应单词tmrtimer定时器wndwindow窗口TMthread message线程消息变量命名中的描述词

34、要尽量用英文,涉及 Windows 对象或 MFC 类时,要采用通用的缩写名称作后缀,Windows 对象及 MFC 类常用名称缩写见表 3-4。【推荐】 表 3-4 Windows 对象与 MFC 类常用名称缩写WindowsMFCWindows 对象例子变量MFC 类例子对象HWNDhWndCWnd*pWndHDLGhDlgCDialog*pDlgHDChDCCDC*pDCHGDIOBJhGdiObjCGdiObject*pGdiObjHPENhPenCPen*pPenHBRUSHhBrushCBrush*pBrushHFONThFontCFont*pFontHBITMAPhBitmapC

35、Bitmap*pBitmapHPALETTEhPaletteCPalette*pPaletteHRGNhRgnCRgn*pRgnHMENUhMenuCMenu*pMenuHWNDhCtlCStatic*pStaticHWNDhCtlCButton*pBtnHWNDhCtlCEdit*pEditHWNDhCtlCListBox*pListBoxHWNDhCtlCComboBox*pComboBox类和对象名应是名词,因为类和对象名用来标明事物,而事物应是名词。基于MFC 基础类的类名、类对象的前、后缀定义见附表 A 基于基础类的类名、类对象的前、后缀定义。3.4.3变量初始化要求成员变量必须在构

36、造函数中进行初始化;【强制】局部变量和全局变量必须在声明的同时进行初始化。【强制】3.4.4全局变量a)严格限制全局变量的使用。在程序中尽可能少的使用全局变量,在决定使用一个全局变量时,要仔细考虑,权衡得失。【推荐】26/ Glbs.cppint g_iMyInt;/定义所有的全局变量/ Glbs.hertern int g_iMyInt;b)明确全局变量的定义。仔细定义并明确全局变量的含义、作用、取值范围、与其它变量间的关系。明确全局变量与操作此全局变量的函数之间的关系,如访问、修改和创建等。【强制】/*本全局变量表示 SCCP 解译错误码,取值如下: / 变量作用、含义0 成功1 错误其它

37、 未用 / 变量取值范围仅 SCCPTranslate()函数可更改该全局变量值,其它模块可通过 GetGTTransErrorCode()函数获得该全局变量/ 使用方法*/BYTE g_GTTranErrorCode;c) 如果全局变量不加以保护,当多个线程调用此函数时,很可能使此变量变为不可知状态。编写可重入函数时,若操作全局变量,则应加以保护。强制假设 g_iExam 是 int 型全局变量,函数 Squre_Exam 返回 Exam 平方值。那么如下函数不具有可重入性。unsigned int example( int iPara )unsigned int uTemp = 0;g_i

38、Exam = iPara; /(*)uTemp = Square_Exam();return uTemp;此函数若被多个线程调用,其结果可能是未知的,因为当(*)语句刚执行完后,另外一个使用本函数的线程可能正好被激活,那么当新激活的线程执行到此函数时,将使 g_iExam 赋与另一个不同的 iPara 值,所以当控制重新回到“uTemp = 27Square_Exam()”后,计算出的 temp 很可能不是预想中的结果。此函数应如下改进:unsigned int example( int iPara )unsigned int uTemp = 0; / 若申请不到“信号量”,说明另外的线程正处

39、于g_iExam = iPara; / 给g_iExam赋值并计算其平方过程中(即正在使用uTemp = Square_Exam();/ 此信号),本线程必须等待其释放信号后,才可继 / 续执行。若申请到信号,则可继续执行,但其它/ 线程必须等待本线程释放信号量后,才能再使用/ 本信号。return uTemp;3.5注释风格 3.5.1注释格式注释应符合以下约定:【强制】单行注释用双斜杠进行注释;多行注释用/* */进行注释;在封存的某一版本的源代码之中不得存在由于调试而留下的大篇的注释。注释一行不要太多,一般 60 个字符以内(保证 VC 集成编辑环境的可见区域之内),如有超过,则换行处理

40、;行末注释尽量对齐;单独注释行和被注释语句缩进相同的空格;注释不要嵌套;注释的频率是:大约每 5 行代码应至少有一行注释;注释行的数量不得少于程序行数量的20%。应尽量使用中文注释,特殊要求除外,如项目要求或工具软件不支持等情况。3.5.2必须注释的部分必须加以注释的部分包括:文件头部注释,见 3.2.2;函数注释,见 3.3.1;类注释,见 4.1;类成员变量,在声明类时要注释成员变量的作用或含义;【强制】28class CMyRectpublic:int m_iLeft;/左上角 X 坐标int m_iTop;/左上角 Y 坐标int m_iRight;/右下角 X 坐标int m_iBo

41、ttom;/右下角 Y 坐标其或者放在成员上部或者放在成员右部,若注释放在成员右部,则所有右部注释部分尽量左对齐。类成员函数,必须注释其用途;【强制】对每个#else 或#endif 给出行末注释,大块的条件语句也应类似处理。【强制】#if (defined(Z_EXECUTE_WHEN_DEBUG)#else / 没有定义 Z_EXECUTE_WHEN_DEBUG 时#endif / end of #if (defined(Z_EXECUTE_WHEN_DEBUG)4类的约定一个定义良好的 VC 软件系统可以分为若干个类的声明、实现以及一个启动类与类交互的主函数体。也就是说,在 VC 里我们

42、的重点将放在类的规格说明上。而一个完整的类的实现主要包含类的描述注释、声明与实现这三部分。4.1类的描述在类的声明之前,要给出适当的注释,主要包括:类名、功能、接口说明、开发者及日期、依赖环境、版本、版权信息、更改记录等。若一个文件只包含一个类,文件头已经注释的内容在此可不再重复罗列。【推荐】/*类名: (必需)功能: (必需)接口说明: (可选)开发者及日期: (必需)29依赖环境: (必需)版本: (可选)版权信息: (可选)更改记录: (若修改过则必需注明) 张三 2010.05.09 0.1 初版张三 2011.06.10 0.4 修改信息收发部分李四 2012.01.02 1.1 增

43、加了信息处理处求算术平均值的功能*/4.2类风格4.2.1类要求a)类的构造应做到模块化、可重用、可维护性好、低复杂度。少的接口以达到低耦合,小的接口(弱耦合)以达到通过接口的信息尽可能少;明确的接口,以达到显而直接的方式;信息的隐藏以达到类的信息对外部存取隐藏起来。【推荐】class Data public:/ 想改变和得到某个数据,使用相应的接口进行访问void SetYear(int y); / 设置数据的接口int GetYear ();/ 得到数据的接口private:/ 理想状态下,通常将所有的数据都声明为privateint year;int month;int day;b)为每

44、一个类显式定义默认构造函数。【强制】class Apublic:A();/ 构造函数A( );int foo();30;c)为每个类都显式定义拷贝构造函数。【推荐】class Pointpublic:Point(int iPointX = 0, int iPointY = 0); / 构造函数Point(Point &p); / 拷贝构造函数private:int iPointX;int iPointY;有成员指针的类不能执行拷贝构造函数,因为编译时会打破隐式共享,并可能导致意外崩溃。d)为每个类都显式重载“=”操作符。【推荐】class Complexpublic:Complex()

45、;/ 默认构造函数Complex(double dReal, double dImag); / 构造函数Complex& operator= (const Complex&);/ 重载“=”操作符有成员指针的类不能执行赋值操作,因为编译时会打破隐式共享,并可能导致意外崩溃。e)为每一个类显式定义析构函数。【推荐】class A public:A( );A( );/ 析构函数int foo( );31f)保证类对象内存被释放之前,基类和派生类的析构函数都被调用。基类的析构函数一定要为虚拟析构函数。【强制】class Apublic:A( ); / 不要这样写virtual int

46、 foo( );void foo1(A* a)delete a;class A public:virtual A( );/ 应该这样写virtual int foo( );void foo1(A* a)delete a;g)在派生类中不要对基类中的非虚函数重新进行定义。如果确实需要在派生类中对该函数进行不同的定义,那么应该在基类中将该函数声明为虚函数。【强制】不要这样写:class Basepublic:void func1(void) ;void func2(int x) ;void func3(int x) ;32class Derived: public Basepublic:void

47、func1(void) ;void func2(int x) ;void func3(int x) ;/ 非虚拟函数是静态约束的。从本质上讲,非虚拟函数会隐藏起相应的基类型版本。/ 为了避免出现具有二元性的行为,禁止对非虚拟函数进行重定义。应该这样写:class Basepublic:virtual void func1(void) ;virtual void func2(int x) ;void func3(int x) ;class Derived: public Basepublic:virtual void func1(void) ;virtual void func2(int x)

48、;void func3_renamed(int x) ;h)推荐用内联函数代替宏函数。同宏函数相比,内联函数不但具有宏函数的效率,而且使用起来更安全。【推荐】不要这样写:#define TABLE_MULT(x) (x) * (x)应该这样写:inline int tablefunction(int i) return i*i;i)为一个类重载了操作符new,则应为这个类重载操作符delete。【强制】不要这样写:#include 33class MemoryPool;class A public:void * operator new(std:size_t); void * operator

49、 new(std:size_t, MemoryPool&); void * operator new(std:size_t, float*); void operator delete(void*, std:size_t, float*);应该这样写:#include class MemoryPool;class A public:void * operator new(std:size_t); void * operator new(std:size_t, MemoryPool&);void * operator new(std:size_t, float*);void op

50、erator delete(void*);void operator delete(void*, MemoryPool&);void operator delete(void*, float*);j)类对外的接口应该是完全功能化的,类中可以定义public的成员函数,但不应该有public的数据成员。【推荐】class A public:int iData;/ 不要这样写;防止使用“public”数据成员。公有数据成员可以被任何用户代码直接访问。使用公有存取成员函数返回数据能防止未经授权的访问。class A private:34int iData;/ 应该这样写public:int

51、accessiData( );k)慎用多继承,以免带来潜在的混淆。【推荐】不要这样写:class A ;class B ;class C : public A, public B ; 应该这样写:class B ;class A : public B ;class C : public B ;4.3类的声明理想情况下,读描述类的声明的头文件,就能知道这个类提供哪些功能,及如何使用这个类。类的结构中至少包含构造函数和析构函数,它的一般形式为:【强制】class 类标识符 public: 构造函数声明 析构函数声明 其它操作的规范声明 private: 内部私有的数据结构 protected: 内

52、部受保护的数据结构下面给出了一个类的注释、声明的简单实例:/*35类名: CMyFile功能: 用于文件的读、写(类的描述)接口说明: 无开发者及日期: 李四-2012.01.02依赖环境: 对软硬件无要求版本: 1.0 版版权信息: Copyright (c) 2001,某某单位更改记录: 张三 2010.05.09 0.1 初版张三 2011.06.10 0.4 修改信息收发部分李四 2012.01.02 1.1 增加了信息处理处求算术平均值的功能*/class CMyFile public: /构造函数,打开指定的文件并初始化(注释在上) CMyFile(const char *cpch

53、File_Name,const char *cpchOpen_Mode); CMyFile();/析构函数声明(注释在右) /从文件读指定的字节到缓冲区; size_t Read_File(const size_t cstruNum_of_record,void *pvBuffer, const size_t cstruSize_of_record); /从缓冲区向文件写入指定的字节; size_t Write_File(const size_t cstruNum_of_record,void *pvBuffer, const size_t cstruSize_of_record); priv

54、ate: FILE *m_pstruFile; /保存打开的文件描述符4.4类的实现类的实现部分只包括成员函数的实现,实现成员函数的一般形式是【强制】:返回类型 类名:成员函数名(参数声明) 语句序列;364.4.1成员函数的参数在向成员函数传递参数时,参数数目不宜多,如果参数个数确实太多,应把几个语义相关的参数组合成一个复合的数据结构。【推荐】假设我们有一个画矩形的函数,传一个 CMyRect 类型的参数比给出四个 int 类型要好一些。class CMyRectpublic:int m_iLeft;/左上角 X 坐标int m_iTop;/左上角 Y 坐标int m_iRight;/右下角

55、 X 坐标int m_iBottom;/右下角 Y 坐标void Draw_Rect(CMyRect cRect);4.4.2成员函数的注释参见 3.3.1函数注释。下面给出一个类的实现定义的例子:/文件名“MyFile.cpp“;/对 CMyFile 类的具体实现#include “MyFile.h”/*函数名:Read_File(const size_t cstruNum_of_record,void *pvBuffer,const size_t size_of_record)功能描述:从文件读指定的字节到缓冲区;字节数等于 cstruSize_of_record* cstruNum_of

56、_record;参数:size_t cstruNum_of_record; 从文件读的记录的个数 I 无符号整数 void *pvBuffer; 存储记录的缓冲区地址 O void 指针 size_t size_of_record;以字节为单位的一个记录的大小 I 无符号整数全局变量:无返回值: size_t38 返回从文件实际读的记录的个数备注:1:当发生错误时返回的从文件实际读的记录个数 2:可能小于 cstruNum_of_record*/size_t CMyFile:Read_File(const size_t cstruNum_of_record, void *pvBuffer,co

57、nst size_t size_of_record); if(fp!=NULL) return(fread(pvBuffer,cstruSize_of_record,cstruNum_of_record,pstruFile); else return 0; /打开指定的文件并初始化私有成员变量 m_pstruFile;CMyFile:CMyFile(const char *cpchFile_Name,const char *cpchOpen_Mode) pstruFile=fopen(cpchFile_Name,cpchOpen_Mode);/在代码内部适当加注释/关闭文件CMyFile: C

58、MyFile() if(pstruFile!=NULL) fclose(pstruFile);/*函数名:Write_File(const size_t cstruNum_of_record,void *pvBuffer,const size_t cstruSize_of_record)功能描述:从缓冲区向文件写入指定的字节;字节数等于 cstruSize_of_record* cstruNum_of_record;参数:size_t cstruNum_of_record; 向文件写的记录的个数 I 无符号整数 void *pvBuffer; 存储记录的缓冲区地址 O void 指针 size

59、_t cstruSize_of_record;以字节为单位的一个记录的大小 I 无符号整数全局变量:无返回值: size_t 返回实际写入文件的记录的个数备注:1:当发生错误时返回的从文件实际读的记录个数39 2:可能小于 cstruNum_of_record*/size_t CMyFile:Write_File(const size_t cstruNum_of_record, void *pvBuffer,const size_t cstruSize_of_record); if (pstruFile!=NULL) return(fwrite(pvBuffer,cstruSize_of_re

60、cord,cstruNum_of_record,pstruFile); else return 0; 我们简单地写一个使用 CMyFile 类的主函数体,主函数体也分为函数体外注释和函数体内的代码及注释。主函数体外注释相对可以简单一些,说明它完成什么功能就可以了。/使用 CMyFile 类将文件“In.txt“拷贝到”Out.txt“的主函数void MainFun(void) /打开文件 CMyFile cFile1(“In.txt“,“rb”);/ 以只读方式打开文件“In.txt“ CMyFile cFile2(“Out.txt “,“wb”);/ 以只写方式打开文件”Out.txt“ char pchBuffer512;/ 存储文件数据的缓冲区 size_

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论