C++基礎知識:泛型編程

1.泛型編程的概念

---不考慮具體數據類型的編程模式

Swap 泛型寫法中的 T 不是一個具體的數據類型,而是泛指任意的數據類型.


2.函數模板

- 函數模板其實是一個具有相同行爲的函數家族,可用不同類型進行調用
- 函數模板可以根據類型實參對函數進行推導調用
- 函數模板可以顯示的指定類型參數
- 函數模板可以被重載
 

①函數模板的語法規則
―template    關鍵字用於聲明開始進行泛型編程
―typename  關鍵字用於聲明泛指類型

 ②函數模板的應用
―自動類型推導調用
―具體類型顯示調用

 

 3.函數模板的深入理解
― 編譯器並不是把函數模板處理成能夠處理任意類型的函數
― 編譯器從函數模板通過具體類型產生不同的函數
― 編譯器會對函數模板進行兩次編譯
  - 在聲明的地方對模板代碼本身進行編譯
  - 在調用的地方對參數替換後的代碼進行編譯


4.函數模板與重載

函數模板可以像普通函數一樣被重載
  C++ 編譯器優先考慮普通函數
   如果函數模板可以產生一個更好的匹配 , 那麼選擇模板
  可以通過空模板實參列表的語法限定編譯器只通過模板匹配

注意:

5.多參數函數模板

函數模板可以定義任意多個不同的類型參數

當聲明的類型參數爲返回值類型時 , 無法進行自動類型推導。

不完美解決方案:
將返回類型參數聲明到第一個參數位置 , 調用時只需顯示聲明返回類型參數即可。

 

 6.類模板

一些類主要用於存儲和組織數據元素
―如 : 數組類 , 鏈表類,鏈表類 , Stack類,Queue類等等
C++中可以將模板的思想應用於類中,使得類的可以不關注具體所操作的數據類型,而只關注類所需要實現的功能 :

聲明的泛指類型 T 可用於聲明成員變量和成員函數
編譯器對類模板的處理方式和函數模板相同
― 編譯器從類模板通過具體類型產生不同的類
― 編譯器在聲明的地方對類模板代碼本身進行編譯
― 編譯器在使用的地方對參數替換後的代碼進行編譯

由於類模板的編譯機制不同 , 所以不能像普通類一樣分開實現後在使用時只包含頭文件,在工程實踐上 , 一般會把類模板的定義直接放到頭文件中!!
只有被調用的類模板成員函數纔會被編譯器生成可執行代碼!!!

 

 類模板可以被特化:用 template<>聲明一個類時, 表示這是一個特化類!

 特化類模板的意義:
  當類模板在處理某種特定類型有缺陷時 , 可以通過類模板的特化來克服處理這種特定類型帶來的不足

注意:編譯器優先選擇特化類生成對象!!

 

類模板的局部特化:可以指定類模板的特定實現 , 並要求某些類型參數仍然必須得模板的用戶指定

爲什麼需要特化,而不重新定義新類 ?
― 特化和重新定義新類看上去沒有本質區別, 但是如果定義新類, 那麼將變成一個類模板和一個新類,使用的時候需要考慮究竟是用類模板還是用新類
― 而特化可以統一的方式使用類模板和特化類 , 編譯器自動優先選擇特化類

 

非類型模板參數的限制:
  -函數模板和類模板的模板參數可以是普通數值
  -變量不能作爲模板參數
  -浮點數和類對象不能作爲模板參數
  -全局指針不能作爲模板參數
  -編譯器的推導過程是在編譯階段完成的, 因此,編譯器的推導必須依賴於特化類,否則推導過程無法結束。

怎麼判斷一個變量是否爲指針???(模板與可變參數函數)

-C++中仍然支持C語言中的可變參數函數
-C++編譯器的匹配調用優先級
  重載函數
  函數模板
  可變參數函數

 

工程問題:內存泄露,內存多次釋放,使用越界...

內存越界的問題常發生於數組的使用中
―解決方案 : 數組類
―工程中, 在非特殊情況下 , 要求開發者使用預先編寫的數組類對象代替C 語言中的原生數組

②內存泄漏和內存多次釋放常發生於指針的使用過程中
―解決方案: 智能指針
―工程中 , 要求開發者使用預先編寫的智能指針類對象代替 C 語言中的原生指針

工程中的智能指針是一個類模板:
  ―通過構造函數接管申請的堆內存
  ―通過析構函數確保堆內存被及時釋放
  ―通過重載指針運算符* 和 - > 模擬指針的行爲
  ―通過重載比較運算符 == 和 != 模擬指針的比較

 

7.智能指針的深入理解:

STL常用的7種智能指針:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、

             boost::shared_array、boost::weak_ptr、boost:: intrusive_ptr

①std::auto_ptr:

 

(1)    儘量不要使用“operator=”。如果使用了,請不要再使用先前對象。

 

(2)    記住 release() 函數不會釋放對象,僅僅歸還所有權。

 

(3)    std::auto_ptr 最好不要當成參數傳遞(讀者可以自行寫代碼確定爲什麼不能)。

 

(4)    由於 std::auto_ptr 的“operator=”問題,有其管理的對象不能放入 std::vector 等容器中。
 

②boost::scoped_ptr

(1)scoped_ptr 沒有 release 函數

(2)沒有重載 operator=,不會導致所有權轉移,但無法賦值,拷貝智能指針。
 

boost::shared_ptr
(1)專門用於共享所有權,內部使用引用計數use_count() ,因此可以支持複製、參數傳遞等,也是用於管理單個堆內存對象的

(2)同樣沒有release() 函數。

 

boost::scoped_array

(1)用於管理動態數組

(2) boost::scoped_array<Simple> my_memory(new Simple[2]); // 使用內存數組來初始化

(3)scoped_ptr 沒有重載 operator*

(4)沒有重載 operator=

⑤boost::shared_array

內部使用了引用計數,可以複製,通過參數來傳遞。

⑥boost::weak_ptr

是專門爲 boost::shared_ptr 而準備的,boost::weak_ptr 只對 boost::shared_ptr 進行引用,而不改變其引用計數,
當被觀察的 boost::shared_ptr 失效後,相應的 boost::weak_ptr 也相應失效

⑦boost::intrusive_ptr

這是一種插入式的智能指針,內部不含有引用計數,需要程序員自己加入引用計數。

智能指針總結:

 

1、在可以使用 boost 庫的場合下,拒絕使用 std::auto_ptr,因爲其不僅不符合 C++ 編程思想,而且極容易出錯[2]。

 

2、在確定對象無需共享的情況下,使用 boost::scoped_ptr(當然動態數組使用 boost::scoped_array)。

 

3、在對象需要共享的情況下,使用 boost::shared_ptr(當然動態數組使用 boost::shared_array)。

 

4、在需要訪問 boost::shared_ptr 對象,而又不想改變其引用計數的情況下,使用 boost::weak_ptr,一般常用於軟件框架設計中。

 

5、最後一點,也是要求最苛刻一點:在你的代碼中,不要出現 delete 關鍵字(或 C 語言的 free 函數),因爲可以用智能指針去管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章