程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 關於編程風格的討論6

關於編程風格的討論6

編輯:關於C++

六、模塊化規范:

為了提高軟件的重用性,減少重復開發的工作量。同時也為了提高程序的可讀性,方便程序的維護,必須加強軟件的模塊化工作。模塊化應該遵循以下幾個基本規范:

1、 個函數應該作到精而小,函數的代碼應該控制在一個適度的規模,每個函數的代碼一般不能超過150行,如果超過這個規模,應該進行模塊化的工作。對於一些特殊的函數確實要超過150行,應該提交出來討論,通過後,要求編寫者更加詳細的對函數注釋,並寫明函數超行的原因,以及設計思想等。

2、 某一功能,如果重復實現三遍以上,既應該考慮模塊化,將其寫成通用函數。並向開發人員發布。並要求將接口文檔和實現的功能備案。

3、 每一個開發人員要盡可能的利用其他人的現成的模塊,減少重復開發。

4、 對函數進行模塊化時,要考慮函數的層次關系,特別是在增加新的功能模塊時,對原來的函數代碼要進行認真的調整,做到相同功能的不同函數沒有重復代碼,此要求的目的在於便於代碼維護。舉例如下:

現有如下函數:

//從szFileName文件中取 ......
long ...... cmGetSomething(const char * c_szFileName,......)
{
CFile * pFile;//用來保存打開文件的地址
pFile=new CFile(c_szFileName,CFile::modeRead);//用創建一個只讀文件
if(pFile==NULL)
{
lResult=CM_POINT_IS_NULL;
goto END;
}
//從文件中讀取......
......
//關閉文件
delete pFile;
END:
return lResult;
}

若現在需要增加如下接口的新函數:

long ...... cmReadSomething(CFile * pFile)
{
if(pFile==NULL)
{
lResult=CM_POINT_IS_NULL;
goto END;
}
//從文件中讀取......
......
END:
return lResult;
}

則要求如下:

將 long ......cmGetSomething(const char * c_szFileName,......)改為

long ...... cmGetSomething (const char * c_szFileName,......)
{
CFile * pFile; //用來保存打開文件的地址
long lResult=CM_OK;//錯誤返回碼
//打開文件
pFile=new CFile(c_szFileName,CFile::modeRead);
if(pFile==NULL)
{
lResult=CM_POINT_IS_NULL;
goto END;
}
//從文件中讀取......
lResult=cmReadSomething(pFile,......);
IF_ERROR_GOTO_END
//關閉文件
delete pFile;
END:
return lResult;
}

模塊化的一些注意事項:

① 、設計好模塊接口,用面向對象的觀點看,包括:函數接口和變量接口。

② 、定義好接口以後不要輕易改動,並在模塊開頭(文件的開頭或函數的開頭)加以說明,所以在定義接口時,一定要反復琢磨,保持風格一致。

③ 、注意全局變量也是一種接口,如果不是確實必要,應該盡量少用全局變量。

④ 、在函數接口中,盡量使函數的接口容易理解和使用,其中每個輸入輸出參數都只代表一種類型數據,不要把錯誤值和其他專用值混在函數的其他輸入輸出參數中。

⑤ 、爭取編寫出永遠成功的函數,使調用者不必進行相應的錯誤處理。

此規范為試行版,解釋權屬於**軟件公司技術委員會!員工在編寫程序時請參閱FuncTemplate.h和FuncTemplate.cpp

FuncTemplate.h
//////////////////////////////////////////////////////////////////////
//工程: FuncTemplate.h //
//描述: 用來處理對二叉樹的一些算法,以及矩陣內存分配。 //
//版本: FuncTemplate 1.0版。 //
//////////////////////////////////////////////////////////////////////
typedef struct _NODE //定義一個節點
{
struct _NODE * pLeftChild; //節點的左孩子
struct _NODE * pRightChild; //節點的右孩子
} NODE;
//==================================================================//
// 功能: 用循環來實現二叉樹的左序遍歷 //
// 參數: pNode //
//(入口) pNode: 二叉樹的入口地址,即根節點的地址。 //
//(出口) 無。 //
// 返回: long 的函數返回碼,如果返回值為CM_OK,表成功遍歷,返回 //
// CM_POINT_IS_NULL表二叉樹指針為空。 //
//==================================================================//
long cmWalkTreeUseCycle(const NODE * pNode);
//==================================================================//
// 功能: 對矩陣進行分配內存 //
// 參數: wRowSize,wColSize,ppplMatrix //
//(入口) wRowSize:矩陣的行數; //
//(入口) wColSize:矩陣的列數; //
//(入口) ppplMatrix:要分配的矩陣的地址; //
//(出口) ppplMatrix:分配的矩陣的地址; //
// 返回: long 的錯誤號,如果返回值為CM_OK,表分配成功,返回 //
// CM_POINTER_IS_NOT_NULL表矩陣的入口地址值不為空。 //
// CM_MEM_ALLOC_FAILED 系統的內存不足 //
//==================================================================//
long cmInitMatrix(const size_t wRowSize,const size_t wColSize,long *** ppplMatrix);
FuncTemplate.cpp
//////////////////////////////////////////////////////////////////////
//工程: FuncTemplate.cpp //
//作者: ** //
//修改者: **,*** //
//描述: 用來處理對二叉樹的一些算法,以及矩陣內存分配。
//主要函數:cmWalkTreeUseCycle,cmInitMatrix
//版本: FuncTemplate 1.0版。
//完成日期:2000-8-26 //
//修改日期: 2000-8-27,2001-12-21 //
//參考文獻: 圖形程序開發人員指南(機械工業出版社)
//////////////////////////////////////////////////////////////////////
#define STRICT
#include "stdio.h"
#include "stdlib.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "makehresult.h"
#include "memory.h"
#include "functemplate.h"
#define CM_MEM_POINTER_IS_NULL CMEMAKEHR(0X100) //表示指針不為空的錯誤
#define CM_MEM_POINTER_IS_NOT_NULL CMEMAKEHR(0X101) //表示指針不為空的錯誤
#define MAX_PUSHED_NODES 100 //定義最大壓棧數量
////程序函數說明開始
//==================================================================
// 功能: 用循環來實現二叉樹的左序遍歷
// 參數: cpNode //
//(入口) cpNode: 二叉樹的入口地址,即根節點的地址。
//(出口) 無。 //
// 返回: long 的函數返回碼,如果返回值為CM_OK,表成功遍歷,返回
// MS_POINT_IS_NULL表二叉樹指針為空。
// 調用方法:在調用此函數前必須先初始化二叉樹
// 思路: 如果正在訪問某節點,如果該節點有左分枝,就先訪問左分枝。
// 接著訪問該節點,如果該節點還有右分支。就再訪問右分支。
// 訪問左分枝時,在該處棧中做標記,當處理完左分枝就訪問此
// 處。訪問完每一個節點後,如果該節點沒有右孩子,並且棧已經
// 為空,那麼對該節點的訪問就完成,代碼對每一個節點都重復以
// 上*想*作。 //
// 參閱: 圖形程序開發人員指南(機械工業出版社)Page:927
// 日期: 2000/8/26.9:40--2000/8/26.21:45
//==================================================================
//圖解:
// 根節點
// @
// / \
// / \
// 左孩子@ @右孩子
// / \ / \
// / \ / \
// @ @ @ @
// 左孩子 右孩子左孩子 右孩子
HRESULT cmWalkTreeUseCycle(const NODE * cpNode)
////程序函數說明結束
{
HRESULT lResult;//用來保存返回的錯誤號。
NODE * pNodeStack[MAX_PUSHED_NODES];//用來作為節點的堆棧。
NODE ** ppNodeStack;//用來指示節點堆棧的指針。
lResult=CM_OK;
//判斷樹是否為空。
if(cpNode !=NULL)
{
pNodeStack[0]=NULL; //設置堆棧為空。
ppNodeStack=pNodeStack+1;
for(;
{
//如果當前的節點有左孩子,對當前點壓棧。
//並把當前點移到左孩子,開始遍歷左子樹,
//如此,直到找到沒有左孩子的節點。
while (cpNode->pLeftChild!=NULL)
{
*ppNodeStack++=(NODE*)cpNode;
cpNode=cpNode->pLeftChild;
}
//我們現在處於沒有左孩子的節點,所以訪問
//節點,如果有右子樹,然後訪問右子樹。或
//後入的節點。重復節點的出棧直到我們找到
//有右子樹的節點,或所有節點出棧
for(;
{
//訪問節點(調用別的函數,沒有實現)
cmVisitNode(cpNode);
//如果節點有右孩子,使該孩子成為當前節
//點並開始遍歷其子樹,否則回朔訪問節點
//直到我們發現一個有右子樹的節點,或所
//有的入棧點已經被訪問。
if(cpNode->pRightChild!=NULL)
{
cpNode=cpNode->pRightChild;
break;
}
//出棧下一個節點,我們可以訪問它,並判
//斷是否有右子樹。
if((cpNode=*(--ppNodeStack))==NULL)
{
//棧為空並且當前節點沒有右子樹,完
//成遍歷。
lResult =CM_OK;
goto END;
}
}
}
}
//如果指針為空則設置返回值信息為MS_POINT_IS_NULL。
lResult=CM_POINTER_IS_NULL;
END:
return lResult;
}
////程序函數說明開始
//==================================================================
// 功能: 對矩陣進行分配內存
// 參數: cwRowSize,cwColSize,ppplMatrix
//(入口) cwRowSize:矩陣的行數;
// cwColSize:矩陣的列數;
// ppplMatrix:要分配的矩陣的地址;
//(出口) ppplMatrix:分配的矩陣的地址;
// 返回: long 的錯誤號,如果返回值為CM_OK,表分配成功,返回
// CM_POINTER_IS_NOT_NULL表矩陣的入口地址值不為空。
// CM_MEM_ALLOC_FAILED 系統的內存不足
// 調用方法:在調用此函數前必須先對傳入值賦空。對傳入值作引用。
// 如:定義: long ** pplMatrix;對pplMatrix賦空,即:
// pplMatrix=NULL; 調用為:cmInitMatrix(10,10,&pplMatrix);
// 思路: 先對每一行分配內存,再對每一行對應的列分配內存。
// 參閱: 無
// 修改人:
// 日期: 2000/8/29.9:40--2000/8/29.16:45
//==================================================================
HRESULT cmInitMatrix(const size_t cwRowSize,const size_t cwColSize,long *** ppplMatrix)
////程序函數說明結束
{
HRESULT lResult; //存儲返回值。
lResult=CM_OK;
WORD wI; //循環變量
//要求對傳入值進行初始化NULL.
if(**ppplMatrix!=NULL)
{
lResult=CM_POINTER_IS_NOT_NULL;
goto END;
}
//對矩陣的行進行分配內存
**ppplMatrix=(long*)malloc(cwRowSize*sizeof(long*));
//如果分配失敗則返回。
if((**ppplMatrix)==NULL)
{
lResult=CM_MEM_ALLOC_FAILED;
goto END;
}
//對每一行所擁有的列數進行分配內存。
for(wI=0;wI<cwRowSize;wI++)
{
*ppplMatrix=(long**)malloc(cwColSize* sizeof(long));
//如果分配失敗則返回錯誤。
if(*ppplMatrix==NULL)
{
lResult=CM_MEM_ALLOC_FAILED;
goto END;
}
//對內存置為零
memset(*ppplMatrix,0,cwColSize*sizeof(long));
}
END:
//對錯誤進行處理。
if(FAILED(lResult))
//如果分配不成功則釋放內存。
if(**ppplMatrix!=NULL)
{
//對每一行內存進行釋放。
for(wI=0;wI<cwRowSize;wI++)
{
if(*ppplMatrix!=NULL)
{
free(*ppplMatrix);
*ppplMatrix=NULL;
}
}
//對列的內存進行釋放。
free(**ppplMatrix);
**ppplMatrix=NULL;
}
return lResult;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */

錯誤處理擴展:

makehresult.h
//////////////////////////////////////////////////////////////////////////////
//作者: **
//描述: 用來對返回代碼的統一規定
//主要函數:
//參考文獻:COM技術內幕(微軟組件對象模型);[美]Dale Rogerson著
//////////////////////////////////////////////////////////////////////////////
#ifndef __ERRORDEFINE_H__
#define __ERRORDEFINE_H__
#include "winerror.h"
//圖解
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-----------+-------------------+
// |Sev|C|R| 設備代碼 | 類編碼 | 返回代碼 |
// +---+-+-+-----------------------+-----------+-------------------+
//
//==============================================================
////對設備代碼的定義
//對通用函數定義的設備代碼
#define FACILITY_CM 0x80
//對虛擬現實函數定義的設備代碼
#define FACILITY_VR 0x81
//對圖象函數定義的設備代碼
#define FACILITY_IMG 0x82
//===================================================================================
//定義類編碼(後16位中的前6位)
//從0X00~0X3F//
//其中0X38~0X3F為給程序員保留的臨時類編碼。
//標准類編碼從0X00~0X37
#define MEMORY_CLASS 0x01
#define FILE_CLASS 0x02
/*
#define TEMP_CLASS1 0X38
#define TEMP_CLASS2 0X39
#define TEMP_CLASS3 0X3A
#define TEMP_CLASS4 0X3B
#define TEMP_CLASS5 0X3C
#define TEMP_CLASS6 0X3D
#define TEMP_CLASS7 0X3E
#define TEMP_CLASS8 0X3F
*/
//=======================================================================
//制作臨時資源時位的前3位屏蔽(即為保存8個臨時類),臨時資源從0X0000~0X1FFF(程序員輸入值)
//實際為0XE000~0XFFFF(宏轉換後)
#define ADDTEMPCLASS(lResult) ((0X38<10)|lResult)
//定義返回通用函數的返回代碼類型
//對lResult的傳入值在0X0000~0X1FFF之間
#ifndef CMEMAKEHR
#define CMSMAKEHR(lResult) MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_CM,ADDTEMPCLASS(lResult))
#define CMEMAKEHR(lResult) MAKE_HRESULT(SEVERITY_ERROR,FACILITY_CM,ADDTEMPCLASS(lResult))
#endif //CMEMAKEHR
//定義返回虛擬現實函數的返回代碼類型
//對lResult的傳入值在0X0000~0X1FFF之間
#ifndef VREMAKEHR
#define VRSMAKEHR(lResult) MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_VR,ADDTEMPCLASS(lResult))
#define VREMAKEHR(lResult) MAKE_HRESULT(SEVERITY_ERROR,FACILITY_VR,ADDTEMPCLASS(lResult))
#endif //VREMAKEHR
//定義返回圖象函數的返回代碼類型
//對lResult的傳入值在0X0000~0X1FFF之間
#ifndef IMGEMAKEHR
#define IMGSMAKEHR(lResult) MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_IMG,ADDTEMPCLASS(lResult))
#define IMGEMAKEHR(lResult) MAKE_HRESULT(SEVERITY_ERROR,FACILITY_IMG,ADDTEMPCLASS(lResult))
#endif //IMGEMAKEHR
//當發生返回代碼時,轉到END處
//要求返回代碼號用lResult,標記號用END
#define IF_ERROR_GOTO_END if(FAILED(lResult)) goto END;
//顯示返回代碼的描述信息
#define DISPLAY_HRESULT_MESSAGE if(FAILED(lResult)) cmDispResultMessage(lResult);
typedef long HRESULT;
typedef long LRESULT;
//===================================================================
//保持和windows系統(com)一致
#define CM_OK S_OK
#define CM_FALSE E_FAIL
#define VR_OK S_OK
#define VR_FALSE E_FAIL
#define IMG_OK S_OK
#define IMG_FALSE E_FAIL
#define CM_UNKNOW_ERROR CMEMAKEHR(0X000) //未知的錯誤
//內存錯誤
#define CM_MEM_ALLOC_FAIL CMEMAKEHR(0X001) //內存分配失敗
#define CM_MEM_FREE_FAIL CMEMAKEHR(0X002) //內存釋放失敗
#define CM_INVALID_POINTER CMEMAKEHR(0X003) //無效的指針
//文件*想*作
#define CM_CREATE_FILE_FAIL CMEMAKEHR(0X010) //文件創建失敗
#define CM_OPEN_FILE_FAIL CMEMAKEHR(0X011) //文件打開失敗
#define CM_CLOSE_FILE_FAIL CMEMAKEHR(0X012) //文件關閉失敗
#define CM_DELETE_FILE_FAIL CMEMAKEHR(0X013) //文件刪除失敗
#define CM_FILE_HAS_EXISTED CMEMAKEHR(0X014) //文件已經存在
#define CM_COPY_FILE_FAIL CMEMAKEHR(0X015) //文件拷貝失敗
#define CM_FILE_NOT_OPEN CMEMAKEHR(0X016) //文件沒有打開
#define CM_READ_FILE_FAIL CMEMAKEHR(0X017) //文件讀取失敗
#define CM_FIND_FILE_FAIL CMEMAKEHR(0X018) //文件查找失敗
#define CM_FILE_HAS_ERROR CMEMAKEHR(0X019) //文件本身有錯
#define CM_WRITE_FILE_FAIL CMEMAKEHR(0X020) //文件寫入失敗
//數組*想*作
#define CM_ARRAY_BEYOND CMEMAKEHR(0X060) //數組越界
//函數*想*作
#define CM_PARAM_BEYOND CMEMAKEHR(0X030) //參數越界
//數據庫*想*作
#define CM_OPEN_DATABASE_FAIL CMEMAKEHR(0X040) //數據庫打開失敗
#define CM_OPEN_TABLE_FAIL CMEMAKEHR(0X041) //數據表打開失敗
#define CM_TABLE_BEYOND CMEMAKEHR(0X042) //數據表訪問越界
#define CM_CREATE_DSN_FAIL CMEMAKEHR(0X043) //創建數據源失敗
#define CM_TABLE_EXIST CMEMAKEHR(0X044) //表已經存在
#define CM_DATABASE_NOT_OPEN CMEMAKEHR(0X045) //數據庫沒有打開
//其他*想*作
#define CM_BEYOND_PARAM CMEMAKEHR(0x100) //參數越界
#define CM_POINT_IS_INVALIAD CMEMAKEHR(0x101) //點為非法的點
//圖象*想*作
#define CM_CREATE_BMP_FAIL CMEMAKEHR(0x200) //創建位圖失敗
//線程*想*作
#define CM_THREAD_IS_LOCK CMEMAKEHR(0x300) //線程背鎖住
//數學計算
#define CM_EDGENUM_NOTENOUGH CMEMAKEHR(0x500) //邊數不夠
//網絡*想*作
#define CM_CONNECT_FAIL CMEMAKEHR(0x700) //連接失敗
//三維設備*想*作
#define DD_CREATE_DEVICE_FAIL CMEMAKEHR(0x400) //創建設備失敗
#define DD_DELETE_DEVICE_FAIL CMEMAKEHR(0x401) //刪除設備失敗
#endif //__ERRORDEFINE_H__
#ifndef __ERRORMATCH_H__
#define __ERRORMATCH_H__
#include "errordefine.h"
#include "windows.h"
//errormatch.h
//用來對錯誤的匹配
#define lResultCount 128
#define IF_ERROR_DISPLAY_MESSAGE if(FAILED(lResult)) {DisplayChineseMessage(lResult); goto END;}
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) {if(p) {delete (p);(p)=NULL;}}
#endif
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) {if(p) {delete[] (p);(p)=NULL;}}
#endif
//===============================================================================
typedef struct _RESULTINFOS //顯示返回代碼信息
{
long lResultNo; //返回代碼號
char szResultMessageChinese[40]; //返回代碼的中文描述
char szResultMessageEnglish[40]; //返回代碼的英文描述
}RESULTINFOS;
//================================================================================
static RESULTINFOS sResultInfo[lResultCount]=
{
{CM_MEM_ALLOC_FAIL,"內存分配失敗","Memeroy"},
{CM_MEM_FREE_FAIL,"內存釋放失敗","Memeroy"},
{CM_INVALID_POINTER,"無效的指針","Memeroy"},
{CM_CREATE_FILE_FAIL,"內存分配失敗","Memeroy"},
{CM_OPEN_FILE_FAIL,"文件打開失敗","Memeroy"},
{CM_CLOSE_FILE_FAIL,"文件關閉失敗","Memeroy"},
{CM_FILE_HAS_EXISTED,"文件已經存在","Memeroy"},
{CM_COPY_FILE_FAIL,"文件拷貝失敗","Memeroy"},
{CM_FILE_NOT_OPEN,"文件沒有打開","Memeroy"},
{CM_READ_FILE_FAIL,"文件讀取失敗","Memeroy"},
{CM_FIND_FILE_FAIL,"文件查找失敗","Memeroy"},
{CM_FILE_HAS_ERROR,"文件本身有錯","Memeroy"},
{CM_WRITE_FILE_FAIL,"文件寫入失敗","Memeroy"},
{CM_ARRAY_BEYOND,"數組越界","Memeroy"},
{CM_PARAM_BEYOND,"參數越界","Memeroy"},
{CM_OPEN_DATABASE_FAIL,"數據庫打開失敗","Memeroy"},
{CM_OPEN_TABLE_FAIL,"數據表打開失敗","Memeroy"},
{CM_TABLE_BEYOND,"數據表訪問越界","Memeroy"},
{CM_CREATE_DSN_FAIL,"創建數據源失敗","Memeroy"},
{CM_TABLE_EXIST,"表已經存在","Memeroy"},
{CM_DATABASE_NOT_OPEN,"數據庫沒有打開","Memeroy"},
{CM_CREATE_BMP_FAIL,"創建位圖失敗","Memeroy"},
{CM_THREAD_IS_LOCK,"線程背鎖住","Memeroy"},
{CM_POINT_IS_INVALIAD,"點為非法的點",""},
{DD_CREATE_DEVICE_FAIL,"創建設備失敗",""},
{DD_DELETE_DEVICE_FAIL,"刪除設備失敗",""}
};
static char * GetChineseMessage(HRESULT lResult)
{
for(long lI=0;lI<lResultCount;lI++)
{
if(sResultInfo[lI].lResultNo==lResult)
{
return sResultInfo[lI].szResultMessageChinese;
}
}
return NULL;
}
static char * GetEnglishMessage(HRESULT lResult)
{
for(long lI=0;lI<lResultCount;lI++)
{
if(sResultInfo[lI].lResultNo==lResult)
{
return sResultInfo[lI].szResultMessageEnglish;
}
}
return NULL;
}
static void DisplayChineseMessage(HRESULT lResult)
{
MessageBox(NULL,GetChineseMessage(lResult),"錯誤!",MB_OK);
}
static void DisplayEnglishMessage(HRESULT lResult)
{
MessageBox(NULL,GetEnglishMessage(lResult),"error!",MB_OK);
}
#endif//__ERRORMATCH_H__

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved