“封裝”的進階思考–片段

來源:互聯網
上載者:User

 


mso-ascii-font-family:"Courier New"'>〖輕鬆一刻〗:BMW和一塊帆布

mso-ascii-font-family:"Courier New"'>天要下雨了,車場上一輛BMW,工作人員拿一塊帆布將它蓋得嚴嚴實實。丁小明和南老師經過時看到了這一幕。

mso-ascii-font-family:"Courier New"'>丁小明:“看,那塊帆布就是一種封裝,它保護了底下的BMW"Courier New"'>不受風吹雨打。”

mso-ascii-font-family:"Courier New"'>南鬱:“不,真正的封裝,是BMW自身,這輛車才是完美的封裝藝術”。

 

"Courier New";mso-hansi-font-family:"Courier New"'>“封裝”有這麼多內容嗎?有些教材,不就是把“publicmso-hansi-font-family:"Courier New"'>、protected"Courier New"'>、private宋體;mso-ascii-font-family:"Courier New";mso-hansi-font-family:"Courier New"'>”一提,就結束了有關“封裝”的內容嗎?讓我們回顧一下本章的曆程。

宋體;mso-ascii-font-family:"Courier New";mso-hansi-font-family:"Courier New"'>

 

Wingdings;font-weight:normal">Ø  不變式是類的靈魂

"Courier New";mso-hansi-font-family:"Courier New"'>要懂得“封裝”,文法與語義上第一件要理解的是“thismso-hansi-font-family:"Courier New"'>”指標,知道它是被編譯器偷會為成員函數的偷偷加一個入參,就是它。然後要能理解就算是一個看起來一個空空的類,它也會有一些“預設的行為”。

"Courier New";mso-hansi-font-family:"Courier New"'>但是,關於封裝的第一件有“靈魂”的事,是“類的不變式”。讓我們來複習一下這些沒有靈魂的封裝:

Code:
  1. int x, y;  

 

"Courier New";mso-hansi-font-family:"Courier New"'>說這就是一個座標?這是裸奔。封裝都談不上,哪來的靈魂。

Code:
  1. struct Point  
  2. {  
  3.         int x, y;  
  4. };  

"Courier New";mso-hansi-font-family:"Courier New"'>

"Courier New";mso-hansi-font-family:"Courier New"'>代碼閱讀者的心理負擔因為這個結構的存在,而減輕了很多,但它也就如此了,  "Courier New"'>不存在更多資訊的封裝。

Code:
  1. class Point  
  2. {  
  3. public:  
  4.   
  5.         int GetX() const { return _x; }  
  6.   
  7.         int GetY() const { return _y; }  
  8.   
  9.    
  10.   
  11.         void SetX(int x) { _x = x; }  
  12.   
  13.         void SetY(int y) { _y = y; }  
  14.   
  15. private:  
  16.   
  17.         int _x, _y;  
  18. };  

 

"Courier New";mso-hansi-font-family:"Courier New"'>這是冗餘保護,structmso-hansi-font-family:"Courier New"'>穿上了小馬甲搖身變成class"Courier New"'>,可是我們還是認得出它。

"Courier New";mso-hansi-font-family:"Courier New"'>物件導向技術本來就是用來對付足夠複雜的問題的。如果面對的是一個簡單的程式中的某個簡單的事物(此處的座標點),那麼structmso-hansi-font-family:"Courier New"'>版本的Point"Courier New"'>就是最佳選擇。如果面對的是一個複雜的程式中的一個簡單的對象,冗餘保護的那個版本值得借鑒。

"Courier New";mso-hansi-font-family:"Courier New"'>一個類型,可能有十數個成員資料,但如果這些成員資料之間彼此沒有什麼關係,那麼很可能它就只適合做一個結構;或者,它只有一個內部資料,但它在和外部打交道時,需要在多種狀態之間按照某種規律切換,那麼這個類也需要我們好好去封裝,以維護它的 "Courier New"'>“不變式”。

Wingdings;font-weight:normal">Ø  需要拷貝構造和賦值嗎?

"Courier New";mso-hansi-font-family:"Courier New"'>當一個類在構造對象時,需要分配額外資源,通常就需要一個配套的解構函式,用以在對象消逝前釋放資源。當然,並不是說資源只能在析構時釋放,但通常會是個好時機可以確保資源被安全回收。

"Courier New";mso-hansi-font-family:"Courier New"'>如果僅僅是這樣,那倒也簡單,一對一地寫構造和解構函式就是了;但是想到對象還會以另一個對象為模子建立出來,這就需要一個拷貝建構函式了。再想到對象還可以彼此間賦值,於是要重載賦值操作符,這下子要放下自己原來已有的,然後再接受對方已經有的……這些過程,都要考慮“深拷貝”或“淺拷貝”問題。

"Courier New";mso-hansi-font-family:"Courier New"'>是時候做一個提示了:並不是所有類(的對象)都需要“拷貝”或“賦值”的。比如寫一個視窗(Windows)"Courier New";mso-hansi-font-family:"Courier New"'>程式,會有許多和視窗類別,這些類通過就在需要時構造出一個實際視窗,很少需要進行“拷貝”,或者讓Amso-hansi-font-family:"Courier New"'>視窗賦值給B"Courier New"'>視窗。再比如,我們自己定製的某些容器類(比如前述的IntegerList"Courier New"'>),在實際應用中,有時候沒有複製整條鏈表的需求。

"Courier New";mso-hansi-font-family:"Courier New"'>當某個類不需要 "Courier New"'>“拷貝構造”或“相互賦值”的能力時,可以直接明了的將這兩個函式宣告為私人的:

Code:
  1. class FontDialog  
  2.   
  3. {  
  4.   
  5. public:  
  6.   
  7.         FontDialog(std::string const& title)  
  8.   
  9.                : _title(title)  
  10.   
  11.         {}  
  12.   
  13.    
  14.   
  15.         ~FontDialog() {}  
  16.   
  17. private:  
  18.   
  19.         FontDialog(FontDialog const& o);  
  20.   
  21.         FontDialog& operator = (FontDialog const& o);  
  22.   
  23.    
  24.   
  25.         std::string _title;     
  26.   
  27. };  

 

"Courier New";mso-hansi-font-family:"Courier New"'>注意:我們把FontDialog"Courier New";mso-hansi-font-family:"Courier New"'>的拷貝構造和賦值操作符聲明為私人的,這就代表了外部再也不能調用這兩個函數,既然外部不會調用這兩個函數,自然我們也就不需去真正實現它們。

"Courier New";mso-hansi-font-family:"Courier New"'>下面的代碼通過不過編譯:

Code:
  1. FontDialog dlgA("Select font ...");  
  2. FontDialog dlgB(dlgA); //編譯不過,因為調用私人的成員函數  
  3.   
  4. FontDialog dlgC("");  
  5. dlgC = dlgA; //也編譯不過,原因同上  

 


mso-ascii-font-family:"Courier New"'>〖小提示〗:STL 容器裡的元素,必須“可複製”

STL的容器,預設採用“值”儲存。並且由於要支援添加,排序等,所以元素之間 經常需要複製,所以想要放入STL"Courier New"'>標準容器的對象,都必須能拷貝及賦值。不過,如果一個對象在實際邏輯上確實不能複製,這時如果又需要放在容器裡,最正確的做法就是只在容器裡儲存它們的指標(相應的,通過需要將元素在堆裡分配)。

 -------------------------------------------------------------------------------

 如果您想與我交流,請點擊如下連結成為我的好友:
http://student.csdn.net/invite.php?u=112600&c=f635b3cf130f350c

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.