1 / 43

第十五章

第十五章. 樣板( Template ). 第十五章 樣板( Template ). 樣板是 C++ 為了方便能夠快速生產程式而提供的新功能,在最初期的 C++ 版本中,並不提供樣板機制。所謂樣板( Template ),就是讓某些特定功能的程式如同板模般,當我們需要大量使用該功能時,直接由編譯器代為改變程式細節,以符合輸入的資料型態。

Download Presentation

第十五章

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第十五章 樣板(Template)

  2. 第十五章樣板(Template) • 樣板是C++為了方便能夠快速生產程式而提供的新功能,在最初期的C++版本中,並不提供樣板機制。所謂樣板(Template),就是讓某些特定功能的程式如同板模般,當我們需要大量使用該功能時,直接由編譯器代為改變程式細節,以符合輸入的資料型態。 • 因此,在現代化的程式設計中,大多將函式或類別設計為樣板,避免撰寫相同功能但資料型態不同的程式。在正式介紹樣板之前,請讀者注意一點,繼承與樣板都能增進程式碼重複使用率及減少程式開發時程,但樣板的對象是固定是類別和函式,而繼承僅限於類別,兩者在許多方面有根本上的不同。

  3. 大綱 • 15.1 什麼是樣板? • 15.2 函式樣板 • 15.2.1 單一保留資訊的函式樣板 • 15.2.2 多保留資訊的函式樣板 • 15.3 類別樣板 • 15.4 樣板的具現 • 15.5 本章回顧

  4. 15.1 什麼是樣板? • 在C語言中,程式設計師常常會遇到一個麻煩的問題,就是即使函式需求相同,但必須針對不同資料型態,設計不同的函式,例如我們想要求出絕對值,就必須設計成兩個名稱不同的函式,如下範例。

  5. 15.1 什麼是樣板? • 在初期的C++中,上述情況獲得改善,我們可以利用函式覆載(Overload)功能,將函式名稱設定為相同的abs,只要引數內容不同即可,如下範例。 • 雖然C++提供了覆載函式來解決函式名稱的問題,但仍無法解決撰寫重複程式碼的問題(雖然通常只需要複製程式碼並略為修改即可),而後期的C++則提供了樣板來解決上述問題。樣板允許保留一些資料,等到實際使用樣板時,才於編譯時期,由編譯器自行複製程式內容。

  6. 15.1 什麼是樣板? • 事實上,樣板可分為兩大類:函式樣板(Function Template)及類別樣板(Class Template),而其目的則分別是為了加強的函式和類別的開發速度。有了樣板,我們只需預先設計一個通用的板模,然後當我們需要設計類似功能的函式或類別時,就套用這個樣板,並設定相關必要的資訊就可以了。

  7. 15.1 什麼是樣板? • 舉例來說,假設我們有一個交換函式swap函式如下,它可以作整數資料的交換。 • 在設計上述的swap函式樣板時,我們可以將程式碼內的int資料型態設定為保留資訊,當我們作整數交換時,只要套用這個樣板,並設定資料型態為int;當我們需要作字元交換,也是同樣可以套用這個樣板,只要將資料型態設定為char即可。換句話說,一個經過設計的樣板,可以讓我們節省很多撰寫類似程式碼的時間,因為編譯器將代為處理套用樣板時的函式轉換手續。

  8. 15.2 函式樣板 • C++的樣板有函式樣板與類別樣板兩種,我們先從簡單的函式樣板開始介紹,我們將函式樣板的宣告分為兩大類語法來加以介紹,即單一保留資訊的函式樣板與多保留資訊的函式樣板。

  9. 15.2.1 單一保留資訊的函式樣板 • 單一保留資訊的函式樣板宣告與定義: • 單一保留資訊的函式樣板宣告語法如下: • 單一保留資訊的函式樣板定義語法如下: • 語法說明: • (1)N是欲保留的資訊,也就是能被替換的資料型態,編譯器將依據呼叫時的資料型態,產生對應的變化。 • (2)class關鍵字可改為typename。 • (3)函式回傳型態也可以宣告為N(保留資訊)。 template <class N> 函式回傳型態 函式名稱(N,N,...); template <class N> 函式回傳型態 函式名稱(N 引數1,N 引數2,...) { ...樣板內容… }

  10. 15.2.1 單一保留資訊的函式樣板 • (4)由於C++是自由格式,因此常見到將宣告列改為兩行的格式,如下定義格式: • 【觀念及實用範例15-1】:實作swap函式樣板,並在呼叫函式樣板時,傳入不同的資料型態。 • 範例15-1:ch15_01.cpp(檔案位於隨書光碟 ch15\ch15_01.cpp)。 template <class N> 函式回傳型態 函式名稱(N 引數1,N 引數2,...) { ...樣板內容… }

  11. 15.2.1 單一保留資訊的函式樣板

  12. 15.2.1 單一保留資訊的函式樣板 樣板(套用char資料型態): a1 = i , b1 = j Swap: a1 = j , b1 = i ------------------------- 樣板(套用int資料型態): a2 = 25 , b2 = 56 Swap: a2 = 56 , b2 = 25 ------------------------- 樣板(使用double資料型態): a3 = 0.7 , b3 = 9.3 Swap: a3 = 9.3 , b3 = 0.7 • 執行結果 • 範例說明: • (1)第11行,函式樣板宣告。第13~20行,函式樣板定義。對照上述範例,我們可以發現,定義中,僅將原本的int改寫為保留資訊T而已。

  13. 15.2.1 單一保留資訊的函式樣板 • (2)當我們宣告swap為函式樣板後,每一次呼叫swap函式時,只要輸入正確的資料時,編譯器會先判斷是否為正確的指標或正確的資料型態,然後依照所判斷的資料型態自動產生相對應的程式碼。例如為了因應第35行的呼叫,編譯器會自動將樣板複製並取代保留資訊,成為下列程式碼:

  14. 15.2.1 單一保留資訊的函式樣板 • (3)當我們在呼叫函式樣板的時候,代入的引數會決定這個函式樣板的內部資料型態。因此在第35行,編譯器判斷及處理的流程如下圖。 圖15-1 編譯器判斷及處理函式樣板的流程

  15. 15.2.2 多保留資訊的函式樣板 • 有時候,我們想要保留的資訊不只一個的時候,C++仍允許我們建立樣板,只要將欲保留的資訊一一宣告即可,如下語法: • 多保留資訊的函式樣板宣告語法如下: • 多保留資訊的函式樣板定義語法如下: • 語法說明: • (1)N1、N2…是欲保留的資訊,引數型態則可宣告為這些保留資訊的任一種。 • (2)class關鍵字可改為typename。 • (3)函式回傳型態也可以宣告為N1或N2…….(即保留資訊之一)。 template <class N1,class N2,……….> 函式回傳型態 函式名稱(N1或N2或…,N1或N2或…,...); template <class N1,class N2,………> 函式回傳型態 函式名稱(N1或N2或… 引數1, N1或N2或… 引數2,..); { ...樣板內容… }

  16. 15.2.2 多保留資訊的函式樣板 • (4)假設我們有兩個保留資訊及兩個引數,則下列是一個合法的宣告範例: • (5)然而我們常常在使用函式樣板時,會不小心使用錯誤的語法,例如下列幾個錯誤範例:

  17. 15.2.2 多保留資訊的函式樣板 • 【觀念範例15-2】:函式樣板中包含多個保留資訊。 • 範例15-2:ch15_02.cpp(檔案位於隨書光碟 ch15\ch15_02.cpp)。

  18. 15.2.2 多保留資訊的函式樣板 • 執行結果 m= 3,p=5, m的p次方=243 n=1.5,p=5, n的p次方=7.59375

  19. 15.2.2 多保留資訊的函式樣板 • 範例說明: • (1)第11行,函式樣板宣告。第13~21行,函式樣板定義。我們在樣板中保留了兩項資訊,T1與T2,其中T2只用在引數宣告與函式定義,而T1則同時用在函式回傳值、引數宣告與函式定義。 • (2)在第27行呼叫power(m,p)時,它將會建構下列的程式碼。

  20. 15.2.2 多保留資訊的函式樣板 • (3)在第28行呼叫power(n,p)時,它將會建構下列的程式碼。 • 對於T1被引數及回傳值同時引用的部分,或許讀者會產生疑惑,在上述說明中,似乎編譯器只要確定引數的資料型態後,就決定了保留資訊應該被取代為哪一種資料型態。例如呼叫power(m,p)時,T1被確認為int,在呼叫power(n,p)時,T1被確認為double。而若我們將回傳值使用另一種型態來接收時,例如int y=power(n,p);,會是什麼樣的狀況呢?答案是會產生警告訊息,編譯器仍將T1認為是double,因此回傳double資料型態的資料,當然最終結果y仍舊是被強制轉型的整數,在上例中,y將會是7。

  21. 15.3 類別樣板 • 樣板除了可以應用於函式外,也可以應用於類別,這樣的類別稱之為『類別樣板』。經過樣板化的類別,其內的成員函式與成員變數可適用於所有的資料型態,只要將某些資訊宣告為保留資訊即可。類別樣板的宣告及定義與函式樣板大同小異,運作原理也差不多,如下所述。 • 首先讓我們先來看看類別樣板的標準宣告格式如下: • 類別樣板的定義語法如下: template <class N> class 類別名稱 { 保護等級: 函式回傳型態 函式名稱(N 引數1,N 引數2,...); //成員函式 ... N 變數名稱; //成員變數 ... }

  22. 15.3 類別樣板 • 類別樣板的成員函式,若定義於類別外部,則語法如下: • 類別樣板產生物件語法: • 語法說明: • (1)N是欲保留的資訊,如果保留資訊不只一個,也可以按照<class N1,class N2,…>等格式擴充。 template <class N> 函式回傳型態 類別樣板名稱 <N>::成員函式名稱( ) { …. 函式定義內容… } 類別樣板名稱 <保留資訊的資料型態> 物件名稱;

  23. 15.3 類別樣板 • (2)< >內的class關鍵字可改為typename。 • (3)函式回傳型態也可以宣告為保留資訊之一。 • (4)宣告類別樣板內的成員函式,並在類別外部定義成員函式時,除了必須在前面加上template <class N>,原本的類別名稱,應該改為『類別樣板名稱 <N>』。 • (5)利用類別樣板產生物件時,也同樣必須加上保留資訊的資料型態,例如<int>、<float>。 • (6)常見的類別樣板宣告錯誤範例如下: • 錯誤範例 • 和函式樣板一樣的限制,類別樣板的引數型態定義不可以在類別中重複使用,如下例的Type。

  24. 15.3 類別樣板

  25. 15.3 類別樣板 • 【觀念及實用範例15-3】:使用類別樣板,使得氣泡排序法可以接受各種資料型態。 • 範例15-3:ch15_03.cpp(檔案位於隨書光碟 ch15\ch15_03.cpp)。

  26. 15.3 類別樣板

  27. 15.3 類別樣板 • 執行結果 ----整數陣列已建立---- 請輸入第0個元素:24 請輸入第1個元素:17 請輸入第2個元素:32 請輸入第3個元素:19 24 17 32 19 --------排序後------- 17 19 24 32 ========================= ----浮點數陣列已建立---- 請輸入第0個元素:15.67 請輸入第1個元素:28.43 請輸入第2個元素:17.52 請輸入第3個元素:12.88 15.67 28.43 17.52 12.88 --------排序後------- 12.88 15.67 17.52 28.43

  28. 15.3 類別樣板 • 範例說明: • (1)第11行,類別樣板宣告。第13~23行,類別樣板定義。我們在樣板宣告保留資訊為T。 • (2)在第70行,類別樣板建立ObjX物件時,T會被指定為int後,由編譯器產生對應的類別程式碼,然後才產生物件。 • (3)在第78行,類別樣板建立ObjY物件時,T會被指定為double後,由編譯器產生對應的類別程式碼,然後才產生物件。

  29. 15.4 樣板的具現 • 在上述的範例說明中,我們不斷地說明,當呼叫函式樣板時,或透過類別樣板宣告物件時,編譯器都會產生一些程式碼。事實上,這個由編譯器自動執行的動作稱之為『樣板的具現(instantiation)』。 • 在編譯時期,編譯器會將樣板依照所給予不同型別的引數,建構出對應的函式或類別。若是經由函式呼叫而造成函式建構的動作,我們稱之為函式樣板的具現;而經過類別的生成物件而造成類別建構的動作,就稱為類別樣板的具現。函式樣板必須在具現後,才能被呼叫,而類別樣板則是必須在具現後,才能夠產生物件。 • 函式樣板的具現與類別樣板的具現可以是獨立的,但也可以有先後關係。這通常發生在類別樣板內又定義了成員函式樣板時。

  30. 15.4 樣板的具現 • 雖然類別樣板已經能夠提高非常好的程式開發效率,但如果成員函式的相似性也很高,我們也可以利用函式樣板進一步定義類別樣板的成員函式,使得程式重複性更低。而此時,定義型態的過程將具有先後的關聯性。 • 我們透過範例15-4,說明編譯器對於樣板的定義流程。範例15-4,將修改自範例15-3,將互換資料另外獨立出來成為swap成員函式,並使用函式樣板來宣告swap函式。 • 【觀念及實用範例15-4】:修改範例15-4,結合類別樣板和函式樣板。 • 範例15-4:ch15_04.cpp(檔案位於隨書光碟 ch15\ch15_04.cpp)。

  31. 15.4 樣板的具現

  32. 15.4 樣板的具現

  33. 15.4 樣板的具現

  34. 15.4 樣板的具現 • 執行結果:(同範例15-3) • 範例說明: • 在類別樣板內,我們又宣告了一個成員函式樣板swap(在第20~26行)。並且在BubbleSort成員函式的第65行呼叫這個成員函式。整個編譯器在編譯過程如下: • Step1: 在第76行,遇到Sort <int> ObjX;,先決定保留資訊T的資料型態為int。 • Step2: 此時T變成了輸入引數資料型態為int的Sort類別,也就是必須將T替換為int產生類別的程式碼。 • Step3: 但編譯器欲產生類別的程式碼時,發現定義了一個成員函式樣板,因此,編譯器必須保留該位置,等到決定BubbleSort成員函式的內容時,找到swap函式樣板的呼叫時,才產生swap函式的程式碼,完成swap函式的具現後,才能夠完成Sort類別的具現。換句話說,具現的過程有如一個堆疊(先進後出),當遇到另一個更深層的具現時,則必須將更深層具現完成後,才能完成較外圍的具現。

  35. 15.5 本章回顧 • 在本章中,我們介紹了C++提供的新功能-『樣板』,善用樣板可以讓我們更有效率地開發中大型專案,減少撰寫相似程式碼的機會,本章重點整理如下: • (1)C++提供了樣板來解決相似程式碼浪費開發時程的問題。樣板允許保留一些資料,等到實際使用樣板時,才於編譯時期,由編譯器自行複製程式內容。 • (2)樣板可分為兩大類:函式樣板(Function Template)及類別樣板(Class Template)。兩者運作的方式和觀念差不多。 • (3)函式樣板的語法如下: • 單一保留資訊的函式樣板宣告語法如下: • 單一保留資訊的函式樣板定義語法如下: template <class N> 函式回傳型態 函式名稱(N,N,...); template <class N> 函式回傳型態 函式名稱(N 引數1,N 引數2,...) { ...樣板內容… }

  36. 15.5 本章回顧 • 多保留資訊的函式樣板宣告語法如下: • 多保留資訊的函式樣板定義語法如下: template <class N1,class N2,……….> 函式回傳型態 函式名稱(N1或N2或…,N1或N2或…,...); template <class N1,class N2,………> 函式回傳型態 函式名稱(N1或N2或…. 引數1, N1或N2或…. 引數2,...); { ...樣板內容… }

  37. 15.5 本章回顧 • (4)類別樣板的相關語法如下: • 類別樣板的定義語法如下: • 類別樣板的成員函式,若定義於類別外部,則語法如下: template <class N> class 類別名稱 { 保護等級: 函式回傳型態 函式名稱(N 引數1,N 引數2,...); //成員函式 ... N 變數名稱; //成員變數 ... } template <class N> 函式回傳型態 類別樣板名稱 <N>::成員函式名稱( ) { ….函式定義內容… }

  38. 15.5 本章回顧 • 類別樣板產生物件語法: • (5)在編譯時期,編譯器會將樣板依照所給予不同型別的引數,建構出對應的函式或類別,這個由編譯器自動執行的動作稱之為『樣板的具現(instantiation)』。發生的時機則發生於函式樣板的呼叫以及類別樣板產生物件時。 • (6)在類別樣板內也可以再定義成員函式的樣板。 類別樣板名稱 <保留資訊的資料型態> 物件名稱;

  39. 本章習題

More Related