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 函數),因爲可以用智能指針去管理。