非議MFC(三)庫程式碼的質量問題 (轉)

worldblog發表於2007-12-14
非議MFC(三)庫程式碼的質量問題 (轉)[@more@]

  非議MFC(三)庫程式碼的質量問題

關鍵字:C++,MFC,RECT,CRect,POINT,CPoint,質量

說明:片斷僅包括理解所必需的程式碼,其餘省略。

每個人的程式碼都不可能完全排除質量隱患,但MFC作為庫程式碼,對其質量怎麼苛求都不會過分。

1.只顧

typedef struct tagRECT
{
  LONG left;
  LONG top;
  LONG right;
  LONG bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;

class CRect : public tagRECT
{
  CPoint& TopLeft();
  CPoint& BottomRight();
};

_AFXWIN_INLINE CPoint& CRect::TopLeft()
  { return *((CPoint*)this); }  1]
_AFXWIN_INLINE CPoint& CRect::BottomRight()
  { return *((CPoint*)this+1); }  2]
TopLeft()透過返回CPoint &同時提供Set和Get功能,並且,返回CPoint &比返回CPoint效率高。但是,的實現必須依賴指標的跨越性轉換(即從CRect *轉換成完全不相干的CPoint *),另外,還要假設是順序存放各資料成員。隨意轉換指標型別,不;依賴編譯器實現,不可移植;以後擴充套件時可維護性降低(如增加資料成員),還有可能導致錯誤(如引入虛擬函式時,有的編譯器將虛表放在地址的前部)。

2.不顧效率

class CRect : public tagRECT
{
  BOOL PtInRect(POINT point) const;
};
因為POINT結構體大於32位地址長度,形參使用值傳遞效率不高,應該改為引用。
的設計應該保持統一的取捨原則,如果說在上一點中,不惜採用那麼極端的方式來提高效率,那麼這裡明顯可以合理提高效率的地方為什麼要放過呢?

3.演算法不嚴謹

class CRect : public tagRECT
{
  BOOL IsRectEmpty() const;
};
IsRectEmpty()函式的功能是當矩形面積為空時返回1;當矩形面積為不空時返回0。
給出如下測試程式碼:
CRect rct(100,100,0,0);
BOOL b=rct.IsRectEmpty();
執行後b的值居然是1!?
有些CRect的成員函式如:IntersectRect()、UnionRect()等只有先NormalizeRect()才能確保獲得正確結果。但IsRectEmpty()完全沒必要依賴NormalizeRect(),例如可以這樣實現:
BOOL CRect::IsRectEmpty() const
{
  return (left==right&&up==bottom ? 1 : 0);
}
推測起來,MFC中的實現可能是:若矩形的right<=left或bottom<=up則返回1。

4.無故破壞約定俗成的規則

class CRect : public tagRECT
{
  void operator=(const RECT& srcRect);
  void operator+=(LPCRECT lpRect);
};
自定義型別不要毫無價值的與內建型別不相容(《Effective C++》語)。operator=()應該返回CRect &,這樣做還可以支援鏈式賦值。同理operator+=()也應該返回CRect &。

5.沒有盡力保證安全性

class CRect : public tagRECT
{
  CRect operator+(LPCRECT lpRect) const;
};
operator+()應該返回const CRect,這樣做可以禁止形如(a+b)=c;的病態語句,同時也保持了與內建型別的行為一致。

6.沒有盡力提高可用性和可靠性

class CDC : public C
{
  BOOL BitBlt(int x, int y, int nWidth, int nHeight, CDC* pSrcDC,
  int xSrc, int ySrc, D dwRop);
};
做個簡單的類比:

size_t  __cdecl strlen(const char *);
形參為什麼要宣告為const char *?因為,其一,const char *既可以接受常量字串又可以接受非常量字串,而char *只能接受非常量字串。其二,const可以保證函式體不更改原字串這一契約。
所以BitBlt()的宣告中,引數pSrcDC是原裝置環境,不會改變,應該宣告為const CDC *。


請參考上一篇《非議MFC(二)邏輯上的不完備》


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-993258/,如需轉載,請註明出處,否則將追究法律責任。

相關文章