研发中心产品一部C++编码规范.docx
《研发中心产品一部C++编码规范.docx》由会员分享,可在线阅读,更多相关《研发中心产品一部C++编码规范.docx(38页珍藏版)》请在冰豆网上搜索。
研发中心产品一部C++编码规范
北京山海经纬信息技术有限公司
产品一部C++编码规范
更新时间:
2009.07
版本:
V2.0.0.0
发布人:
李欣
1.目标
保证程序清晰易读,易于维护,保证产品的可持续性发展
养成良好的编程习惯,减少出错的可能性,提升产品质量
(代码是一项艺术品,程序员是一个专业人员,一个好的习惯利于人利于己)
2.总体原则
代码要简洁、易懂、美观
风格要统一、一致
3.编码规范
1)代码的对齐与缩进
描述:
这是一项美观性方面的要求,但实际上很大程度影响着代码的可读性。
具体要求:
同一级别代码要垂直对齐
不同级别代码要有正确的缩进,缩进应使用Tab键。
起始与终止的花括号“{}”应具有相同的缩进距离,并且均各自处于单独一行,该行不应有其它代码。
示例:
voidCTestDlg:
:
OnButton1()
{
inti=0;
}
if(pDBDriver==NULL)
return;
MessageBox("failed");
try
......
catch(longerrCode)
while(pDBDriver->FetchRecord(rec)==S_OK)
longid;
pDBDriver->GetField_Int32(rec,0,&id);
if(++count<600000)
continue;
if(count>=600100)
break;
for(j=0;j<100;j++)
pClob[j]='A'+(j%26);
switch(type)
case0:
case1:
case2:
typedefenum
EnumRWM_Unknown=0,//unknown
EnumRWM_Append,//appendrecord
EnumRWM_Update,//updaterecord
EnumRWM_Delete,//deleterecord
EnumRecordWriteMode;
enumEnumType
a=1,
b=2,
};
classCLog
public:
virtualvoidWriteLog(constchar*pLine)=0;
virtualvoidWriteText(constchar*pText)=0;
2)代码中的空行
代码中合理的空行同样保证程序的清晰易读。
代码简洁不意味着要删除空行,行数的多少与代码是否简洁无关
在函数体与函数体之间应有空行
在一个函数体内部,应有合适的空行,表示函数体功能的实现是分步进行的
在头文件中声明函数或者变量时,相互无关的函数或变量声明之间通常应有空行
相互关联紧密的语句之间不要有空行,如elseif与elseif之间不能有空行。
一般不应有两个以上连续的空行出现
classCEzRuleLength:
publicCEzRule
CEzRuleLength();
virtual~CEzRuleLength();
virtualEnumEzRuleTypeGetType();
virtualEnumEzRuleCatGetCategory();
virtualvoidGetName(char*pName);
virtualvoidPrepare(void*pDBCnn,longDBCnn);
virtualboolCheckRecord(CEzRecordset*pRecordset,longindex);
virtuallongGetSupportFieldType();
private:
intm_iMinLength;
intm_iMaxLength;
EnumEzRuleTypeCEzRuleLength:
GetType()
returnenum_EzRT_Prop_Length;
EnumEzRuleCatCEzRuleLength:
GetCategory()
returnenum_EzRC_Prop;
//开始检查
boolbPass=true;
intfc=m_arrFieldIndex.size();
for(inti=0;i{CFieldValue*pFV=pRecord->GetFieldValue(m_arrFieldIndex[i]);if(pFV->bIsNull)continue;if((pFV->type&GetSupportFieldType())==0){charmsg[MAX_RULE_NAME+512];sprintf(msg,"规则\"%s\"应用的字段\"\"类型不正确,无法检查",m_strUserName,m_arrApplyField[i].c_str());stException*p=newstException(EnumError_Failed,__LINE__,__FILE__,msg,0);throwp;}intlength=0;switch(pFV->type){caseEnumFType_Int8:caseEnumFType_Int16:caseEnumFType_Int32:caseEnumFType_Int64:{charbuf[64];if(pFV->type==EnumFType_Int8)itoa(pFV->btValue,buf,10);elseif(pFV->type==EnumFType_Int16)itoa(pFV->sValue,buf,10);elseif(pFV->type==EnumFType_Int32)itoa(pFV->lValue,buf,10);else_i64toa(pFV->i64Value,buf,10);intsize=strlen(buf);for(inti=0;i{if(isdigit(buf[i]))length++;}}break;caseEnumFType_String:{length=strlen(pFV->pText);}break;}if(lengthm_iMaxLength){bPass=false;break;}}3)代码中的换行描述:过长的代码很难阅读,需要适当的换行。一些合理的换行可大大提升代码可读性。具体要求:过长的字符串常量可以换行过长的条件判断语句、函数调用可以换行当一个函数参数很多时,为了清晰注释每个参数含义,也可每个参数单独一行换行的位置在“&&”、“||”、“+”、“-”、“*”、“/”,“,”等之后。换行均应缩进。但不要把两个很短的语句放在同一行(如在一行中:min=100;max=0;)。示例:return(EnumFType_Int8|EnumFType_Int16|EnumFType_Int32|EnumFType_Int64|EnumFType_String);sprintf(pBuf,"警告:%s,代码:%d,描述:%s,出错模块ID:%d,文件:%s,行号:%d\r\n",pText,pException->code,pException->desp,pException->ModuleID,fname,pException->linenumber);if((st&EnumProcStatus_NeedInput)!=0&&target.iTargetInputIndex==input)if((status&EnumProcStatus_NeedInput)!=0||(status&EnumProcStatus_NeedInputRestart)!=0){}constchar*pStr="TheMSDNLibraryistheessentialreference""fordevelopers,withmorethan1.5gigabytesof""technicalprogramminginformation,samplecode,";4)代码中的空格描述:适当的空格提升代码可读性,因此推荐在代码中使用合理的空格。具体要求:“+”、“-”、“*”、“”、“&&”、“&”等运算符两侧推荐使用空格隔开函数调用时各个参数之间推荐使用空格隔开只用一个空格进行隔开示例:if((pFV->type&GetSupportFieldType())==0){charmsg[MAX_RULE_NAME+512];sprintf(msg,"规则\"%s\"应用的字段\"\"类型不正确,无法检查",m_strUserName,m_arrApplyField[i].c_str());stException*p=newstException(EnumError_Failed,__LINE__,__FILE__,msg,0);throwp;}5)注释的添加描述:注释描述代码的意图。具体要求:注释用于描述代码的意图,不是用于将代码注释掉,没有用的代码要删除,不存在模棱两可的代码。一个类的注释应在头文件中,类的声明之前进行注释。一个类的成员变量应在头文件中进行注释,一般在成员变量声明的前一行加注释,并且后面应空行。一个类的成员函数一般在cpp文件中进行注释,注释内容包括函数的意图、参数的含义、返回值的含义、是否抛出异常、供谁调用、调用前要求等等。If/elseif/case等函数体中局部变量的注释可以直接写在局部变量声明的后面,位于同一行。函数比较复杂时,可以分步骤增加注释,以便处理过程清晰易懂。如果变量的含义可以从名称上很明显获得,可以不加注释;如果返回值含义可以从类型上或者函数名称上很明显获得,可以不加注释;当使用一个整型、不同数值代表不同含义时,此时必须增加注释清晰说明。示例:public://约束方式//0:第n级代码长度为前面级别定义的所有代码长度之和,默认//例如01,01002,010020001,分别为三个级别的代码//1:第n级代码长度为第n级定义的代码长度//例如01,002,0001,分别为三个级别的代码longm_iClassType;////代码是否已被使用//boolCDlgStdCodeDefine::IsCodeUsed(DBDrv::IDBDriver*pDBDriver,longDBCnn,LPCTSTRlpszCode,longStdID){////getthisformatadaptercapability,returnEnumAdapterCap//longCShpAdapter::GetCap(){return(EnumCap_CanRead|//是否支持读取EnumCap_CanWrite|//是否支持写入EnumCap_IsGeoFormat|//是否可存空间数据EnumCap_HasProjection|//是否具有投影信息EnumCap_CanUpdate|//是否支持对现有数据更新EnumCap_HasAttribute|//是否支持属性EnumCap_CanIndexRecord|//支持索引记录EnumCap_CanUpdateRecord|//支持更新记录EnumCap_CanExecuteSQL|//支持sql查询EnumCap_CanAppend);}if(m_hShape==NULL||m_hDBF==NULL){stException*p=newstException(EnumError_NotOpen,__LINE__,__FILE__,"数据未打开",m_ID);throwp;}bHasFilter=false;//donotsupportsqlfilterif(m_iRecordIndex>=m_iTotalRecordCount){bReachEnd=true;return;}bReachEnd=false;CRecord*pRecord=newCRecord();//getshapeCFieldValue*pShapeField;OGRGeometry*pOGRGeo=SHPReadOGRObject(m_hShape,m_iRecordIndex);if(pOGRGeo==NULL)//nullshape{pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),(CGeometry*)NULL,false);}else{OGREnvelopeenv;pOGRGeo->getEnvelope(&env);if(env.MinX<-1E300||env.MaxX>1E300){OGRGeometryFactory::destroyGeometry((OGRGeometry*)pOGRGeo);pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),(CGeometry*)NULL,false);}else{CGeometry*pGeo=newCGeometry(pOGRGeo);pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),pGeo,false);}}pRecord->AddFieldValue(pShapeField);//adddbffields6)变量的声明和初始化描述:如何定义变量及注意事项。具体要求:在一个类中成员变量的声明要都放在一起(ClassWizard维护的变量例外),一般声明在类的最后,不要和函数穿插着定义。一个类中声明的变量,如其类型为基本类型(如int,double,指针,bool等)需要在构造函数中初始化,如其类型为class(如CString,智能指针,Array等)或者struct等,如果有构造函数则一般不需要初始化,总之不让类的变量处在不可知的状态下。在类的析构函数中必须释放指针等对象,一旦定义指针,就要初始化,一旦初始化,就要在析构中加上释放。在一个函数中局部变量尽量在用到的时候再定义,以利于别人理解代码。函数中的局部变量根据情况看是否需要初始化。一个较大类的成员变量应以“m_”开头,一个很简单类或者结构的成员变量可不以“m_”开头,一个函数体内部的局部变量或者函数参数不能以“m_”开头。通常在成员变量名称的选择上,遵守以下规则:Bool类型以m_b开头整型应以m_i开头double以m_d开头float以m_f开头string以m_str开头一层指针以m_p开头两层指针以m_pp开头智能指针以m_p或者m_ptr开头数组以m_arr开头示例:classCPageSelectTable:publicCPropertyPage{DECLARE_DYNCREATE(CPageSelectTable)public:CPageSelectTable();~CPageSelectTable();//{{AFX_DATA(CPageSelectTable)enum{IDD=IDD_DIALOG_SELECT_TABLE};CListCtrlm_List;BOOLm_bOwner;intm_iViewType;//}}AFX_DATA//{{AFX_VIRTUAL(CPageSelectTable)public:virtualBOOLOnSetActive();virtualBOOLOnWizardFinish();protected:virtualvoidDoDataExchange(CDataExchange*pDX);//}}AFX_VIRTUALprotected:voidFillList();//{{AFX_MSG(CPageSelectTable)virtualBOOLOnInitDialog();afx_msgvoidOnCheckOwner();afx_msgvoidOnRadioTable();afx_msgvoidOnRadioTable2();afx_msgvoidOnChangeEditFilter();afx_msgvoidOnButtonVer();afx_msgBOOLOnHelpInfo(HELPINFO*pHelpInfo);//}}AFX_MSGDECLARE_MESSAGE_MAP()public:boolm_bAllowMultipleSelect;//selectedtablenameCStringArraym_arrSelectTableName;//page1pointerCPageAdoAdapter*m_pPage1;//sdepagepointerCPageSDECnn*m_pPageSDE;//所选择SDE版本CStringm_strVersion;//所选图层的LayerIndexlongm_iSelLayerIndex;};7)函数的声明及实现描述:定义函数的注意事项。具体要求:在一个类中函数的声明都放在一起(ClassWizard维护的变量例外),一般声明在类的前面,不要和变量穿插着定义。严格来说,大部分函数都应该有返回值,至少表示成功或者失败。函数名称的选择应简明并且清晰,并且单词与单词之间应该有大小写的变化,如FindField、LoadFromXML、SaveToXML、RemoveAllFields等等。函数的功能应尽量简单、明确、不应过长,在编写函数时要考虑其以后的重用性。除了特别简单的函数之外,函数体内应只有一个return语句,并将其放在最后,见下面示例。在我们刚开始写一个程序时,有些功能没有封装为一个函数的必要,但是程序在不断的维护、完善过程中,很可能发现一些重复功能可封装为函数供重复调用,此时需仔细考虑函数的封装、重构等,合适的函数封装可大大提升开发效率并减少出错可能。示例:////规则定义//classCEzRule{public:CEzRule();virtual~CEzRule();virtualEnumEzRuleTypeGetType()=0;virtualEnumEzRuleCatGetCategory()=0;virtualvoidGetName(char*pName)=0;virtualvoidLoadFromXml(IUnknown*pRawElement);virtualvoidSaveToXml(IUnknown*pRawDoc,IUnknown**ppRawElement);virtualconstchar*GetUserName();virtualvoidSetUserName(constchar*pName);virtualvoidSetParam(CEzRuleParamSet¶ms);virtualCEzRuleParamSet*GetParam();virtuallongGetCap();virtualvoidAddAuxRecord(CRecord*pRecord);virtualboolCheckRecord(CEzRecordset*pRecordset,longindex);virtuallongGetSupportFieldType();virtualvoidPrepare(void*pDBCnn,longDBCnn);voidAddApplyField(constchar*pFieldName);protected://自定义名称charm_strUserName[MAX_RULE_NAME];//设置参数CEzRuleParam
CFieldValue*pFV=pRecord->GetFieldValue(m_arrFieldIndex[i]);
if(pFV->bIsNull)
if((pFV->type&GetSupportFieldType())==0)
charmsg[MAX_RULE_NAME+512];
sprintf(msg,"规则\"%s\"应用的字段\"\"类型不正确,无法检查",
m_strUserName,m_arrApplyField[i].c_str());
stException*p=newstException(
EnumError_Failed,__LINE__,__FILE__,msg,0);
throwp;
intlength=0;
switch(pFV->type)
caseEnumFType_Int8:
caseEnumFType_Int16:
caseEnumFType_Int32:
caseEnumFType_Int64:
charbuf[64];
if(pFV->type==EnumFType_Int8)
itoa(pFV->btValue,buf,10);
elseif(pFV->type==EnumFType_Int16)
itoa(pFV->sValue,buf,10);
elseif(pFV->type==EnumFType_Int32)
itoa(pFV->lValue,buf,10);
else
_i64toa(pFV->i64Value,buf,10);
intsize=strlen(buf);
for(inti=0;i{if(isdigit(buf[i]))length++;}}break;caseEnumFType_String:{length=strlen(pFV->pText);}break;}if(lengthm_iMaxLength){bPass=false;break;}}3)代码中的换行描述:过长的代码很难阅读,需要适当的换行。一些合理的换行可大大提升代码可读性。具体要求:过长的字符串常量可以换行过长的条件判断语句、函数调用可以换行当一个函数参数很多时,为了清晰注释每个参数含义,也可每个参数单独一行换行的位置在“&&”、“||”、“+”、“-”、“*”、“/”,“,”等之后。换行均应缩进。但不要把两个很短的语句放在同一行(如在一行中:min=100;max=0;)。示例:return(EnumFType_Int8|EnumFType_Int16|EnumFType_Int32|EnumFType_Int64|EnumFType_String);sprintf(pBuf,"警告:%s,代码:%d,描述:%s,出错模块ID:%d,文件:%s,行号:%d\r\n",pText,pException->code,pException->desp,pException->ModuleID,fname,pException->linenumber);if((st&EnumProcStatus_NeedInput)!=0&&target.iTargetInputIndex==input)if((status&EnumProcStatus_NeedInput)!=0||(status&EnumProcStatus_NeedInputRestart)!=0){}constchar*pStr="TheMSDNLibraryistheessentialreference""fordevelopers,withmorethan1.5gigabytesof""technicalprogramminginformation,samplecode,";4)代码中的空格描述:适当的空格提升代码可读性,因此推荐在代码中使用合理的空格。具体要求:“+”、“-”、“*”、“”、“&&”、“&”等运算符两侧推荐使用空格隔开函数调用时各个参数之间推荐使用空格隔开只用一个空格进行隔开示例:if((pFV->type&GetSupportFieldType())==0){charmsg[MAX_RULE_NAME+512];sprintf(msg,"规则\"%s\"应用的字段\"\"类型不正确,无法检查",m_strUserName,m_arrApplyField[i].c_str());stException*p=newstException(EnumError_Failed,__LINE__,__FILE__,msg,0);throwp;}5)注释的添加描述:注释描述代码的意图。具体要求:注释用于描述代码的意图,不是用于将代码注释掉,没有用的代码要删除,不存在模棱两可的代码。一个类的注释应在头文件中,类的声明之前进行注释。一个类的成员变量应在头文件中进行注释,一般在成员变量声明的前一行加注释,并且后面应空行。一个类的成员函数一般在cpp文件中进行注释,注释内容包括函数的意图、参数的含义、返回值的含义、是否抛出异常、供谁调用、调用前要求等等。If/elseif/case等函数体中局部变量的注释可以直接写在局部变量声明的后面,位于同一行。函数比较复杂时,可以分步骤增加注释,以便处理过程清晰易懂。如果变量的含义可以从名称上很明显获得,可以不加注释;如果返回值含义可以从类型上或者函数名称上很明显获得,可以不加注释;当使用一个整型、不同数值代表不同含义时,此时必须增加注释清晰说明。示例:public://约束方式//0:第n级代码长度为前面级别定义的所有代码长度之和,默认//例如01,01002,010020001,分别为三个级别的代码//1:第n级代码长度为第n级定义的代码长度//例如01,002,0001,分别为三个级别的代码longm_iClassType;////代码是否已被使用//boolCDlgStdCodeDefine::IsCodeUsed(DBDrv::IDBDriver*pDBDriver,longDBCnn,LPCTSTRlpszCode,longStdID){////getthisformatadaptercapability,returnEnumAdapterCap//longCShpAdapter::GetCap(){return(EnumCap_CanRead|//是否支持读取EnumCap_CanWrite|//是否支持写入EnumCap_IsGeoFormat|//是否可存空间数据EnumCap_HasProjection|//是否具有投影信息EnumCap_CanUpdate|//是否支持对现有数据更新EnumCap_HasAttribute|//是否支持属性EnumCap_CanIndexRecord|//支持索引记录EnumCap_CanUpdateRecord|//支持更新记录EnumCap_CanExecuteSQL|//支持sql查询EnumCap_CanAppend);}if(m_hShape==NULL||m_hDBF==NULL){stException*p=newstException(EnumError_NotOpen,__LINE__,__FILE__,"数据未打开",m_ID);throwp;}bHasFilter=false;//donotsupportsqlfilterif(m_iRecordIndex>=m_iTotalRecordCount){bReachEnd=true;return;}bReachEnd=false;CRecord*pRecord=newCRecord();//getshapeCFieldValue*pShapeField;OGRGeometry*pOGRGeo=SHPReadOGRObject(m_hShape,m_iRecordIndex);if(pOGRGeo==NULL)//nullshape{pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),(CGeometry*)NULL,false);}else{OGREnvelopeenv;pOGRGeo->getEnvelope(&env);if(env.MinX<-1E300||env.MaxX>1E300){OGRGeometryFactory::destroyGeometry((OGRGeometry*)pOGRGeo);pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),(CGeometry*)NULL,false);}else{CGeometry*pGeo=newCGeometry(pOGRGeo);pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),pGeo,false);}}pRecord->AddFieldValue(pShapeField);//adddbffields6)变量的声明和初始化描述:如何定义变量及注意事项。具体要求:在一个类中成员变量的声明要都放在一起(ClassWizard维护的变量例外),一般声明在类的最后,不要和函数穿插着定义。一个类中声明的变量,如其类型为基本类型(如int,double,指针,bool等)需要在构造函数中初始化,如其类型为class(如CString,智能指针,Array等)或者struct等,如果有构造函数则一般不需要初始化,总之不让类的变量处在不可知的状态下。在类的析构函数中必须释放指针等对象,一旦定义指针,就要初始化,一旦初始化,就要在析构中加上释放。在一个函数中局部变量尽量在用到的时候再定义,以利于别人理解代码。函数中的局部变量根据情况看是否需要初始化。一个较大类的成员变量应以“m_”开头,一个很简单类或者结构的成员变量可不以“m_”开头,一个函数体内部的局部变量或者函数参数不能以“m_”开头。通常在成员变量名称的选择上,遵守以下规则:Bool类型以m_b开头整型应以m_i开头double以m_d开头float以m_f开头string以m_str开头一层指针以m_p开头两层指针以m_pp开头智能指针以m_p或者m_ptr开头数组以m_arr开头示例:classCPageSelectTable:publicCPropertyPage{DECLARE_DYNCREATE(CPageSelectTable)public:CPageSelectTable();~CPageSelectTable();//{{AFX_DATA(CPageSelectTable)enum{IDD=IDD_DIALOG_SELECT_TABLE};CListCtrlm_List;BOOLm_bOwner;intm_iViewType;//}}AFX_DATA//{{AFX_VIRTUAL(CPageSelectTable)public:virtualBOOLOnSetActive();virtualBOOLOnWizardFinish();protected:virtualvoidDoDataExchange(CDataExchange*pDX);//}}AFX_VIRTUALprotected:voidFillList();//{{AFX_MSG(CPageSelectTable)virtualBOOLOnInitDialog();afx_msgvoidOnCheckOwner();afx_msgvoidOnRadioTable();afx_msgvoidOnRadioTable2();afx_msgvoidOnChangeEditFilter();afx_msgvoidOnButtonVer();afx_msgBOOLOnHelpInfo(HELPINFO*pHelpInfo);//}}AFX_MSGDECLARE_MESSAGE_MAP()public:boolm_bAllowMultipleSelect;//selectedtablenameCStringArraym_arrSelectTableName;//page1pointerCPageAdoAdapter*m_pPage1;//sdepagepointerCPageSDECnn*m_pPageSDE;//所选择SDE版本CStringm_strVersion;//所选图层的LayerIndexlongm_iSelLayerIndex;};7)函数的声明及实现描述:定义函数的注意事项。具体要求:在一个类中函数的声明都放在一起(ClassWizard维护的变量例外),一般声明在类的前面,不要和变量穿插着定义。严格来说,大部分函数都应该有返回值,至少表示成功或者失败。函数名称的选择应简明并且清晰,并且单词与单词之间应该有大小写的变化,如FindField、LoadFromXML、SaveToXML、RemoveAllFields等等。函数的功能应尽量简单、明确、不应过长,在编写函数时要考虑其以后的重用性。除了特别简单的函数之外,函数体内应只有一个return语句,并将其放在最后,见下面示例。在我们刚开始写一个程序时,有些功能没有封装为一个函数的必要,但是程序在不断的维护、完善过程中,很可能发现一些重复功能可封装为函数供重复调用,此时需仔细考虑函数的封装、重构等,合适的函数封装可大大提升开发效率并减少出错可能。示例:////规则定义//classCEzRule{public:CEzRule();virtual~CEzRule();virtualEnumEzRuleTypeGetType()=0;virtualEnumEzRuleCatGetCategory()=0;virtualvoidGetName(char*pName)=0;virtualvoidLoadFromXml(IUnknown*pRawElement);virtualvoidSaveToXml(IUnknown*pRawDoc,IUnknown**ppRawElement);virtualconstchar*GetUserName();virtualvoidSetUserName(constchar*pName);virtualvoidSetParam(CEzRuleParamSet¶ms);virtualCEzRuleParamSet*GetParam();virtuallongGetCap();virtualvoidAddAuxRecord(CRecord*pRecord);virtualboolCheckRecord(CEzRecordset*pRecordset,longindex);virtuallongGetSupportFieldType();virtualvoidPrepare(void*pDBCnn,longDBCnn);voidAddApplyField(constchar*pFieldName);protected://自定义名称charm_strUserName[MAX_RULE_NAME];//设置参数CEzRuleParam
if(isdigit(buf[i]))
length++;
caseEnumFType_String:
length=strlen(pFV->pText);
if(lengthm_iMaxLength)
bPass=false;
3)代码中的换行
过长的代码很难阅读,需要适当的换行。
一些合理的换行可大大提升代码可读性。
过长的字符串常量可以换行
过长的条件判断语句、函数调用可以换行
当一个函数参数很多时,为了清晰注释每个参数含义,也可每个参数单独一行
换行的位置在“&&”、“||”、“+”、“-”、“*”、“/”,“,”等之后。
换行均应缩进。
但不要把两个很短的语句放在同一行(如在一行中:
min=100;max=0;)。
return(EnumFType_Int8|EnumFType_Int16|
EnumFType_Int32|EnumFType_Int64|EnumFType_String);
sprintf(
pBuf,
"警告:
%s,代码:
%d,描述:
%s,出错模块ID:
%d,文件:
%s,行号:
%d\r\n",
pText,pException->code,pException->desp,pException->ModuleID,
fname,pException->linenumber);
if((st&EnumProcStatus_NeedInput)!
=0&&
target.iTargetInputIndex==input)
if((status&EnumProcStatus_NeedInput)!
=0||
(status&EnumProcStatus_NeedInputRestart)!
=0)
constchar*pStr="TheMSDNLibraryistheessentialreference"
"fordevelopers,withmorethan1.5gigabytesof"
"technicalprogramminginformation,samplecode,";
4)代码中的空格
适当的空格提升代码可读性,因此推荐在代码中使用合理的空格。
“+”、“-”、“*”、“”、“&&”、“&”等运算符两侧推荐使用空格隔开
函数调用时各个参数之间推荐使用空格隔开
只用一个空格进行隔开
5)注释的添加
注释描述代码的意图。
注释用于描述代码的意图,不是用于将代码注释掉,没有用的代码要删除,不存在模棱两可的代码。
一个类的注释应在头文件中,类的声明之前进行注释。
一个类的成员变量应在头文件中进行注释,一般在成员变量声明的前一行加注释,并且后面应空行。
一个类的成员函数一般在cpp文件中进行注释,注释内容包括函数的意图、参数的含义、返回值的含义、是否抛出异常、供谁调用、调用前要求等等。
If/elseif/case等
函数体中局部变量的注释可以直接写在局部变量声明的后面,位于同一行。
函数比较复杂时,可以分步骤增加注释,以便处理过程清晰易懂。
如果变量的含义可以从名称上很明显获得,可以不加注释;如果返回值含义可以从类型上或者函数名称上很明显获得,可以不加注释;当使用一个整型、不同数值代表不同含义时,此时必须增加注释清晰说明。
//约束方式
//0:
第n级代码长度为前面级别定义的所有代码长度之和,默认
//例如01,01002,010020001,分别为三个级别的代码
//1:
第n级代码长度为第n级定义的代码长度
//例如01,002,0001,分别为三个级别的代码
longm_iClassType;
//
//代码是否已被使用
boolCDlgStdCodeDefine:
IsCodeUsed(DBDrv:
IDBDriver*pDBDriver,longDBCnn,LPCTSTRlpszCode,longStdID)
//getthisformatadaptercapability,returnEnumAdapterCap
longCShpAdapter:
GetCap()
return(EnumCap_CanRead|//是否支持读取
EnumCap_CanWrite|//是否支持写入
EnumCap_IsGeoFormat|//是否可存空间数据
EnumCap_HasProjection|//是否具有投影信息
EnumCap_CanUpdate|//是否支持对现有数据更新
EnumCap_HasAttribute|//是否支持属性
EnumCap_CanIndexRecord|//支持索引记录
EnumCap_CanUpdateRecord|//支持更新记录
EnumCap_CanExecuteSQL|//支持sql查询
EnumCap_CanAppend);
if(m_hShape==NULL||m_hDBF==NULL)
EnumError_NotOpen,__LINE__,__FILE__,"数据未打开",m_ID);
bHasFilter=false;//donotsupportsqlfilter
if(m_iRecordIndex>=m_iTotalRecordCount)
bReachEnd=true;
bReachEnd=false;
CRecord*pRecord=newCRecord();
//getshape
CFieldValue*pShapeField;
OGRGeometry*pOGRGeo=SHPReadOGRObject(m_hShape,m_iRecordIndex);
if(pOGRGeo==NULL)//nullshape
pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),(CGeometry*)NULL,false);
OGREnvelopeenv;
pOGRGeo->getEnvelope(&env);
if(env.MinX<-1E300||env.MaxX>1E300)
OGRGeometryFactory:
destroyGeometry((OGRGeometry*)pOGRGeo);
CGeometry*pGeo=newCGeometry(pOGRGeo);
pShapeField=newCFieldValue(0,m_arrSrcFields[0].c_str(),pGeo,false);
pRecord->AddFieldValue(pShapeField);
//adddbffields
6)变量的声明和初始化
如何定义变量及注意事项。
在一个类中成员变量的声明要都放在一起(ClassWizard维护的变量例外),一般声明在类的最后,不要和函数穿插着定义。
一个类中声明的变量,如其类型为基本类型(如int,double,指针,bool等)需要在构造函数中初始化,如其类型为class(如CString,智能指针,Array等)或者struct等,如果有构造函数则一般不需要初始化,总之不让类的变量处在不可知的状态下。
在类的析构函数中必须释放指针等对象,一旦定义指针,就要初始化,一旦初始化,就要在析构中加上释放。
在一个函数中局部变量尽量在用到的时候再定义,以利于别人理解代码。
函数中的局部变量根据情况看是否需要初始化。
一个较大类的成员变量应以“m_”开头,一个很简单类或者结构的成员变量可不以“m_”开头,一个函数体内部的局部变量或者函数参数不能以“m_”开头。
通常在成员变量名称的选择上,遵守以下规则:
Bool类型以m_b开头
整型应以m_i开头
double以m_d开头
float以m_f开头
string以m_str开头
一层指针以m_p开头
两层指针以m_pp开头
智能指针以m_p或者m_ptr开头
数组以m_arr开头
classCPageSelectTable:
publicCPropertyPage
DECLARE_DYNCREATE(CPageSelectTable)
CPageSelectTable();
~CPageSelectTable();
//{{AFX_DATA(CPageSelectTable)
enum{IDD=IDD_DIALOG_SELECT_TABLE};
CListCtrlm_List;
BOOLm_bOwner;
intm_iViewType;
//}}AFX_DATA
//{{AFX_VIRTUAL(CPageSelectTable)
virtualBOOLOnSetActive();
virtualBOOLOnWizardFinish();
protected:
virtualvoidDoDataExchange(CDataExchange*pDX);
//}}AFX_VIRTUAL
voidFillList();
//{{AFX_MSG(CPageSelectTable)
virtualBOOLOnInitDialog();
afx_msgvoidOnCheckOwner();
afx_msgvoidOnRadioTable();
afx_msgvoidOnRadioTable2();
afx_msgvoidOnChangeEditFilter();
afx_msgvoidOnButtonVer();
afx_msgBOOLOnHelpInfo(HELPINFO*pHelpInfo);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
boolm_bAllowMultipleSelect;
//selectedtablename
CStringArraym_arrSelectTableName;
//page1pointer
CPageAdoAdapter*m_pPage1;
//sdepagepointer
CPageSDECnn*m_pPageSDE;
//所选择SDE版本
CStringm_strVersion;
//所选图层的LayerIndex
longm_iSelLayerIndex;
7)函数的声明及实现
定义函数的注意事项。
在一个类中函数的声明都放在一起(ClassWizard维护的变量例外),一般声明在类的前面,不要和变量穿插着定义。
严格来说,大部分函数都应该有返回值,至少表示成功或者失败。
函数名称的选择应简明并且清晰,并且单词与单词之间应该有大小写的变化,如FindField、LoadFromXML、SaveToXML、RemoveAllFields等等。
函数的功能应尽量简单、明确、不应过长,在编写函数时要考虑其以后的重用性。
除了特别简单的函数之外,函数体内应只有一个return语句,并将其放在最后,见下面示例。
在我们刚开始写一个程序时,有些功能没有封装为一个函数的必要,但是程序在不断的维护、完善过程中,很可能发现一些重复功能可封装为函数供重复调用,此时需仔细考虑函数的封装、重构等,合适的函数封装可大大提升开发效率并减少出错可能。
//规则定义
classCEzRule
CEzRule();
virtual~CEzRule();
virtualEnumEzRuleTypeGetType()=0;
virtualEnumEzRuleCatGetCategory()=0;
virtualvoidGetName(char*pName)=0;
virtualvoidLoadFromXml(IUnknown*pRawElement);
virtualvoidSaveToXml(IUnknown*pRawDoc,IUnknown**ppRawElement);
virtualconstchar*GetUserName();
virtualvoidSetUserName(constchar*pName);
virtualvoidSetParam(CEzRuleParamSet¶ms);
virtualCEzRuleParamSet*GetParam();
virtuallongGetCap();
virtualvoidAddAuxRecord(CRecord*pRecord);
voidAddApplyField(constchar*pFieldName);
//自定义名称
charm_strUserName[MAX_RULE_NAME];
//设置参数
CEzRuleParam
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1