亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C++開發中數據結構和算法的分離

2019-11-17 05:06:15
字體:
來源:轉載
供稿:網友

  相信每一個在windows下編過程序的人都或多或少地用過位圖,大多數人是從網上下載一些成熟完善的DIB類庫來使用(例如CxImage、CDIB),少數人有一套自己封裝好的DIB類庫,方便以后的擴充和使用。(近幾年GDI+異軍突起,在某些處理方面,如:縮放、旋轉、漸變填充等它提供無與倫比的速度和質量,但,假如你想做一個完善的圖像處理程序,直接使用它會給架構設計帶來困難,你可以用adapter模式封裝它后再使用)。

  這時候,假如你需要一些圖像處理操作你會怎么辦呢?很多沒有OO經驗的C++程序員(例如一年前的我)可能會這樣做:在類中直接添加方法。

//================================================================
int FClamp0255 (int nValue) {return max (0, min (0xFF, nValue));} // 飽和到0--255

class FCObjImage
{
 public :
  Invert () ;
  AdjustRGB (int R, int G, int B) ;
} ;
//================================================================
void FCObjImage::Invert ()
{
 if ((GetHandle() == NULL) (ColorBits() < 24))
  return ;

 int nSpan = ColorBits() / 8 ; // 每象素字節數3, 4
 for (int y=0 ; y < Height() ; y++)
 {
  BYTE * pPixel = GetBits (y) ;
  for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
  {
   pPixel[0] = ~pPixel[0] ;
   pPixel[1] = ~pPixel[1] ;
   pPixel[2] = ~pPixel[2] ;
  }
 }
}
//================================================================
void FCObjImage::AdjustRGB (int R, int G, int B)
{
 if ((GetHandle() == NULL) (ColorBits() < 24))
  return ;

 int nSpan = ColorBits() / 8 ; // 每象素字節數3, 4
 for (int y=0 ; y < Height() ; y++)
 {
  BYTE * pPixel = GetBits (y) ;
  for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
  {
   pPixel[0] = FClamp0255 (pPixel[0] + B) ;
   pPixel[1] = FClamp0255 (pPixel[1] + G) ;
   pPixel[2] = FClamp0255 (pPixel[2] + R) ;
  }
 }
}
//================================================================
  這里舉了兩個例子(分別實現反色,調節RGB值功能),現實中會有大量的此類操作:亮度、對比度、飽和度......現在回想一下,你添加這些方法的步驟是什么,Ooooooooo,RCP(我同事的發明,全稱:rapid copy paste^-^),第一步一定是從上面復制一塊代碼下來,然后改掉其中的接口和處理部分。雖然這里的示范代碼很短小,不會連同bug一起復制,但,定時炸彈卻又多了一個。有天,你的boss告訴你:我不能忍受長時間的等待,請給我加個進度條.....。你也許會加個全局變量,也許會給每個函數加個參數,但不變的是:你必須修改所有這些處理函數的代碼,內心的咒罵并不會使你少改其中的任何一個。而此時,bug已經在旁邊伺機而動了...然而苦日子遠沒熬到頭,一個月后,你心血來潮的老板會讓你在其中加上區域處理的功能,再一個月后......

  回頭重新看看代碼?沒錯,除了紅色的代碼外,其他地方一摸一樣,那能不能把這些算法分離抽出來呢?可能我們馬上會想到標準庫中qsort和windows中常用的回調方法。好,讓我們實作一下:

//================================================================void Pixel_Invert (BYTE * pPixel)
{
 pPixel[0] = ~pPixel[0] ;
 pPixel[1] = ~pPixel[1] ;
 pPixel[2] = ~pPixel[2] ;
}
//================================================================
void FCObjImage::PixelPRocess (void(__cdecl*PixelProc)(BYTE * pPixel))
{
 if ((GetHandle() == NULL) (ColorBits() < 24))
  return ;

 int nSpan = ColorBits() / 8 ; // 每象素字節數3, 4
 for (int y=0 ; y < Height() ; y++)
 {
  BYTE * pPixel = GetBits (y) ;
  for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
  {
   PixelProc (pPixel) ;
  }
 }
}
//================================================================
void FCObjImage::Invert ()
{
 PixelProcess (Pixel_Invert) ;
}
//================================================================
  嗯,看樣子不錯,算法被剝離到一個單一函數中,我們似乎已經解決問題了。處理Invert它完成的非常好,但處理AdjustRGB時碰到了麻煩,RGB那三個調節參數怎么傳進去呢?我們的接口參數只有一個,通過添加全局變量/成員變量?這是一個辦法,但隨著類方法的增加,程序的可讀性和維護性會急劇的下降,反而倒不如改之前的效果好。 更多文章 更多內容請看C/C++技術專題  C/C++相關文章  Wlan組網----家庭專題專題,或

那么如何實現高度的抽象和良好的接口呢?我們現場請來OO(object orient),請它來講一下它的實現。設計如下派生關系:
  
C++開發中數據結構和算法的分離

//================================================================
class FCSinglePixelProcessBase
{
 public :
  virtual void ProcessPixel (int x, int y, BYTE * pPixel) PURE ;
} ;
//================================================================
class FCPixelInvert : public FCSinglePixelProcessBase
{
 public :
  virtual void ProcessPixel (int x, int y, BYTE * pPixel) ;
} ;
void FCPixelInvert::ProcessPixel (int x, int y, BYTE * pPixel)
{
 pPixel[0] = ~pPixel[0] ; pPixel[1] = ~pPixel[1] ; pPixel[2] = ~pPixel[2] ;
}
//================================================================
class FCPixelAdjustRGB : public FCSinglePixelProcessBase
{
 public :
  FCPixelAdjustRGB (int DeltaR, int DeltaG, int DeltaB) ;
  virtual void ProcessPixel (int x, int y, BYTE * pPixel) ;
 protected :
  int m_iDeltaR, m_iDeltaG, m_iDeltaB ;
} ;
void FCPixelAdjustRGB::ProcessPixel (int x, int y, BYTE * pPixel)
{
 pPixel[0] = FClamp0255 (pPixel[0] + m_iDeltaB) ;
 pPixel[1] = FClamp0255 (pPixel[1] + m_iDeltaG) ;
 pPixel[2] = FClamp0255 (pPixel[2] + m_iDeltaR) ;
}
//================================================================
  然后我們修改image類如下:

//================================================================
#include "PixelProcessor.h"
class FCObjImage
{
 public :
  void PixelHandler (FCSinglePixelProcessBase & PixelProcessor, FCObjProgress * progress = NULL) ;
} ;
//================================================================
void FCObjImage::PixelHandler (FCSinglePixelProcessBase & PixelProcessor, FCObjProgress * progress)
{
 if (GetHandle() == NULL)
  return ;

 int nSpan = ColorBits() / 8 ; // 每象素字節數3, 4
 for (int y=0 ; y < Height() ; y++)
 {
  BYTE * pPixel = GetBits (y) ;
  for (int x=0 ; x < Width() ; x++, pPixel += nSpan)
  {
   PixelProcessor.ProcessPixel (x, y, pPixel) ;
  }
  if (progress != NULL)
   progress->SetProgress (y * 100 / Height()) ;
 }
}
//================================================================
void FCObjImage::Invert (FCObjProgress * progress)
{
 PixelHandler (FCPixelInvert(), progress) ;
}
void FCObjImage::AdjustRGB (int R, int G, int B, FCObjProgress * progress)
{
 PixelHandler (FCPixelAdjustRGB (R,G,B), progress) ;
}
//================================================================
 ?。ㄒ陨现皇且粋€基本框架,你可以很輕易的把區域處理的參數添加進去-通過構造時傳遞一個RECT參數。)

  對象真的是一個很奇妙的東西,它可以對外提供一個簡單的接口,而自身又可以封裝上很多附加信息。

  好,現在讓我們來檢驗一下剛才的成果:添加一個給圖像奇數行置黑,給偶數行置白的操作。

//================================================================class FCPixelTest : public FCSinglePixelProcessBase
{
 public :
  virtual void ProcessPixel (int x, int y, BYTE * pPixel) ;
} ;
void FCPixelTest::ProcessPixel (int x, int y, BYTE * pPixel)
{
 if (y % 2) pPixel[0]=pPixel[1]=pPixel[2] = 0 ;
 // 奇數行
 else
  pPixel[0]=pPixel[1]=pPixel[2] = 0xFF ;
// 偶數行
}

  然后進行如下調用:


PixelHandler (FCPixelTest(), progress) ;
//================================================================
  多么的和諧美妙,設計算法的人員只需寫出自己的算法,而不用去考慮怎么讓它支持進度條和區域這些問題。感覺這就象一把設計優良的AK,你可以不斷的往里添加子彈(對象)^-^

  至此,我們應該已經大功告成了。還有問題嗎?

  等等,別忙,有些地方不太對,我添加這個算法后,怎么編譯這么久啊。

  問題就出在那個不起眼的:

  #include "PixelProcessor.h"

  image是圖像處理的最底層對象,工程中的所有文件都直接或間接地包含它,因此,任何對image.h本身及它所包含的.h的修改都會引起幾乎整個工程的build,這當然是無法忍受的,解決的辦法是使用“前置聲明”,因為在PixelHandler接口中我們只需要它的引用(也即是說:我(接口)并不需要知道傳給我的類的內部結構,給我一個32(64)的內存地址就OK了)。

  因此我們把

#include "PixelProcessor.h"
  替換成:

class FCSinglePixelProcessBase ; // external class 前置聲明
  然后在.cpp文件中再包含PixelProcessor.h,這樣,對PixelProcessor.h的改變僅僅會導致.cpp文件的重新編譯,大大節約了編譯時間。

  總結:

  1)可能的話,在編程中永遠也別去想“拷貝代碼”這個字眼。究竟,OO就是為了抽象和代碼重用才誕生的。

  2)除非必要,否則類的成員變量和函數的參數盡量用指針或引用代替,這樣做可以在.h中盡可能地少包含其他.h文件,而用前置聲明來替代,以此來減少編譯時間和以后可能會產生的交叉包含。

  3)最后說一下效率問題:有些朋友可能會說每個像素都調用虛函數會影響性能,這的確,但實際的損失遠沒有想象的大。我實測了一下:對1024*768的圖片進行反片處理,速度只有5%左右的損失,進行復雜處理(亮度/對比度/gamma)時損失可完全忽略,究竟多出來的那部分代碼只是進出棧和查表,而不是浮點除這樣耗時的指令。 更多文章 更多內容請看C/C++技術專題  C/C++相關文章  Wlan組網----家庭專題專題,或

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久久久久久久国产| 国产成人免费91av在线| 国产精品日韩在线一区| 精品福利樱桃av导航| 国产精品三级久久久久久电影| 国产在线播放91| 国产精品91在线观看| 亚洲欧洲日产国码av系列天堂| 欧美极品少妇与黑人| 久久精品视频在线播放| 亚洲国产精品美女| 亚洲直播在线一区| 精品福利免费观看| 国产精品十八以下禁看| 一区二区三区精品99久久| 欧美日韩亚洲网| 国产精品都在这里| 日韩激情视频在线| 一区二区三区视频免费在线观看| 奇米4444一区二区三区| 亚洲精品福利资源站| 亚洲人免费视频| 揄拍成人国产精品视频| 日韩美女视频中文字幕| 欧美肥臀大乳一区二区免费视频| 国产精品久久久久一区二区| 欧美国产一区二区三区| 中文字幕在线成人| 日本欧美一二三区| 91九色视频在线| 亚洲国产欧美在线成人app| 欧美一级高清免费| 亚洲大胆美女视频| 精品国产自在精品国产浪潮| 91久久精品久久国产性色也91| 亚洲免费视频一区二区| 久久亚洲精品中文字幕冲田杏梨| 55夜色66夜色国产精品视频| 2023亚洲男人天堂| 国产69精品99久久久久久宅男| 亚洲电影天堂av| 亚洲精品小视频| 国产自摸综合网| 亚洲精品白浆高清久久久久久| 国内成人精品视频| 国产精品毛片a∨一区二区三区|国| 久久精品99久久香蕉国产色戒| 在线观看国产精品91| 中文字幕亚洲色图| 国产精品欧美一区二区| 57pao国产精品一区| 91高潮在线观看| 久久久久久12| 亚洲成人av片在线观看| 国产精品免费久久久久影院| www国产亚洲精品久久网站| 夜夜嗨av色一区二区不卡| 国外成人免费在线播放| 国产精品网站视频| 欧美成人免费在线视频| 国产精品香蕉在线观看| 久久在线免费视频| 久久久久久久久综合| 国产精品欧美激情在线播放| 亚洲天堂免费在线| 亚洲第一精品自拍| 欧美成人在线影院| 国产一区二区三区网站| 国产精品2018| 岛国视频午夜一区免费在线观看| 国产精品小说在线| 日韩精品视频中文在线观看| 91免费看视频.| 91精品久久久久久久久| 国产精品美女久久久久av超清| 国产在线a不卡| 国产91精品久久久久| 国产精品久久久久久久久久久久久久| 国产成人一区二区三区| 91免费的视频在线播放| 97精品视频在线观看| 一区二区在线视频播放| 日韩精品免费在线视频| 欧美国产激情18| 欧美性猛交xxxx乱大交3| 国产日韩在线免费| 欧美视频免费在线| 成人激情黄色网| 精品国产美女在线| yw.139尤物在线精品视频| 国产日韩精品视频| 色综合久久中文字幕综合网小说| 久久精品国产久精国产思思| 亚洲第一精品夜夜躁人人爽| 日本成人激情视频| 日韩av免费看| 亚洲午夜精品久久久久久久久久久久| 亚洲性日韩精品一区二区| 中文字幕精品在线| 亚洲人免费视频| 国产精品久久久久av免费| 久久青草精品视频免费观看| 国产精品久久久久不卡| www欧美日韩| 在线观看久久久久久| 欧美成人精品一区二区| 久久久噜噜噜久久久| 欧美久久久精品| 亚洲在线视频福利| 久久五月天综合| 欧美午夜美女看片| 一区二区三区日韩在线| 亚洲视频国产视频| 亚洲国产精品电影在线观看| 亚洲永久在线观看| 色诱女教师一区二区三区| 国产精品嫩草影院久久久| 亚洲新中文字幕| 国内精品国产三级国产在线专| 日韩视频在线免费| 美女撒尿一区二区三区| 日韩一区在线视频| 色在人av网站天堂精品| 91亚洲精品在线观看| 欧美色videos| 日韩美女视频中文字幕| 国产精品视频午夜| 久久免费视频在线观看| 九九热精品视频国产| 精品久久久久久久大神国产| 精品欧美激情精品一区| 国产精品ⅴa在线观看h| 亚洲少妇激情视频| 91sao在线观看国产| 成人免费在线视频网址| 77777少妇光屁股久久一区| 精品网站999www| 精品国产一区二区三区四区在线观看| 91九色蝌蚪国产| 亚洲综合成人婷婷小说| 亚洲第一av在线| 欧美精品一区在线播放| www.亚洲天堂| 亚洲人av在线影院| 中文字幕欧美亚洲| 性欧美亚洲xxxx乳在线观看| 午夜精品国产精品大乳美女| www.国产精品一二区| 久久久国产精品x99av| 一区二区三区天堂av| 国产精品男人爽免费视频1| 97国产精品久久| 热久久视久久精品18亚洲精品| 国产午夜精品一区理论片飘花| 91最新国产视频| 成人午夜一级二级三级| 中文字幕亚洲欧美日韩2019| 亚洲xxxxx| 久久精品国产欧美亚洲人人爽| 亚洲精品xxx| 一个人看的www久久| 日韩女优在线播放| 国产精品久久久久av| 亚洲日本中文字幕免费在线不卡|