Download presentation
Presentation is loading. Please wait.
Published byEvelyn Silas Clarke Modified over 9 years ago
1
Chapter 14 Templates (樣板) Chapter 14 Templates (樣板)
2
14.1 Introduction 是考慮以下程式問題: ◦ 請撰寫一個函式將一個整數陣列中的每個元素依序印出。 ◦ 如果現在我們也想把字元陣列、浮點數陣列、字 串陣列的元素印出的話,跟怎麼作? 必須另外為特定的型態來撰寫此型別專屬的副函式! 樣板( template )的作用即用來解決這樣的問題。 void printArray(const int a[], const int count) { for (int i=0; i<count; i++) cout << a[i] << “ “; cout << endl; }
3
14.1 Introduction Function templates and class templates ◦ Programmers are enable to specify an entire range of related functions and related classes Function-template specializations and class-template specializations can be generated, respectively. ◦ Generic programming
4
Software Engineering Observation 14.1 Most C++ compilers require the complete definition of a template to appear in the client source-code file that uses the template. For this reason and for reusability, templates are often defined in header files, which are then #included into the appropriate client source-code files. ◦ For class templates, this means that the member functions are also defined in the header file.
5
14.2 Function Templates Function Templates ◦ Used to produce overloaded functions that perform identical operations on different types of data First, programmer writes a single function-template definition. Compiler generates separate object-code functions (function-template specializations) based on argument types in calls to the function template
6
14.2 Function Templates Function-template definitions ◦ Starting with a template header Keyword template List of template parameters Enclosed in angle brackets ( ) Each template parameter is preceded by keyword class or keyword typename (both are interchangeable) Used to specify types of arguments to, local variables in and return type of the function template Examples template
7
Common Programming Error 14.1 Not placing keyword class or keyword typename before each type template parameter of a function template is a syntax error.
8
fig14_01.cpp (1 of 2) Type template parameter T specified in template header 注意:樣板的定義由 template 開始,角刮號中一定至 少要定義一種型態或類別
9
fig14_01.cpp (2 of 2) Creates a function-template specialization of printArray where int replaces T Creates a function-template specialization of printArray where double replaces T Creates a function-template specialization of printArray where char replaces T
10
Common Programming Error 14.2 If a template is invoked with a user-defined type, and if that template uses operators (e.g., ==, +, <=) with objects of that class, those operators must be overloaded. Forgetting to overload such operators causes compilation errors.
11
Indicate Any Error #include using namespace std; class Test { public: Test(int s=0) { a = s; } private: int a; } template void printArray(const T *a, const int count) { for (int i=0; i<count; i++) cout << a[i] << endl; } void main () { Test b[4]; printArray(b, 4); } Error: How to fix?
12
Performance Tip 14.1 Remember that multiple function-template specializations are instantiated in a program (at compile time), despite the fact that the template is written only once. ◦ For the example of fig14_01.cpp, three specialized functions are generated and compiled: printArray(const int *, const int); printArray(const double *, const int); printArray(const char *, const int);
13
14.4 Class Templates Class templates (or parameterized types) ◦ Class-template definitions start with a header such as template ◦ Additional type parameters can be specified using a comma-separated list. For example template
14
14.4 Class Templates 使用類別樣板( class template )的時機: ◦ 樣板的寫法並非適用於實作所有的類別。 如果類別成員函式的運算大多與成員變數的存取有關,或 類別過於複雜,較不適合採用樣板來實作。 如果類別的功用主要作為一種資料結構,單純作為資料的 「容器」,則比較適合以樣板來實作。 例如,堆疊、佇列、鏈結串列等。 本節將以「堆疊」( Stack )來說明類別樣板 的實作語法。
15
An Introduction to Stack A kind of data structure Last-In-First-Out (LIFO) Push (A) Push (B) Push (C) Push (D) Push (E) Pop () Which one is popped by the function Pop()? A B C D E Add a new item on the top of stack. Get the item the item at the top of stack and remove it from the stack. top 0 1 2 3 4 5
16
Examples of Stack 01234 0 1 2 3 4 (0, 0) (0, 1) (1, 1) (1, 0) (2, 0) (2, 1) (3, 1) (3, 0) (4, 0) (4, 1) (3, 2)
17
An Implementation of Stack Implement Stack using an array. ◦ Assume integer elements are considered. class Stack { public: Stack (int = 10); //Default constructor ~Stack(); bool push (int); //Push an integer into the stack; return true if successful bool pop (int &); //Pop an integer from the stack; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int top; //initialized to -1; always maintain the next index to pop int *stackPtr; };
18
Stack (int s) : size( (s > 0)? s : 10 ), top(-1) { stackPtr = new int[size]; } ~Stack() { delete [] stackPtr; } bool Stack::push (int pushValue) { if (!isFull()) { stackPtr[++top] = pushValue; return true; } return false; } bool Stack:: pop (int &popValue) { if (!isEmpty()) { popValue = stackPtr[top--]; return true; } return false; } bool Stack::isFull () const { return (top == size); } bool Stack::isEmpty () const { return (top == -1); }
19
An Implementation of Stack Now consider object elements. class Stack { public: Stack (int = 10); //Default constructor ~Stack(); bool push (const Point &); //Push a Point object into the stack; return true if successful bool pop (Point &); //Pop a Point object from the stack; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int top; //initialized to -1; always maintain the next index to pop Point *stackPtr; }; class Point { public: Point(int a=0, int b=0) : x(a), y(b) { } private: int x, y; };
20
Stack (int s) : size( (s > 0)? s : 10 ), top(-1) { stackPtr = new Point[size]; } ~Stack() { delete [] stackPtr; } bool Stack::push (int pushValue) { if (!isFull()) { stackPtr[++top] = pushValue; return true; } return false; } bool pop (int &popValue) { if (!isEmpty()) { popValue = stackPtr[top--]; return true; } return false; } bool Stack::isFull () { return (top == size); } bool Stack::isEmpty () { return (top == -1); } 請注意,陣列中如果每個元素都 是物件,在呼叫每個物件的建構 子時不會給引數,因此請記得為 你的資料類別(如本例的 Point ) 提供預設建構子。 請注意此兩行敘述。 在這兩行中,涉及物件的指定。因為最 好為資料類別(如本例的 Point )提供拷 貝建構子與賦值運算子多載函式。 請注意此兩行敘述。 在這兩行中,涉及物件的指定。因為最 好為資料類別(如本例的 Point )提供拷 貝建構子與賦值運算子多載函式。
21
Observations Stack 的操作在於物件的建立與指定,其運作與資料 的內容無關。 ◦ Stack 不需要是 Point 類別的夥伴類別;因為 Stack 的運作沒有 讀取其成員變數的必要。 Stack 扮演「容器」的角色;代表其當中存放的內容 (型態)隨時會改變。 ◦ 內容一改變,就必須重新實作新的 Stack 類別?! ◦ 解決方法:利用樣板( template )
22
Stack.h (1 of 3) 這一行寫在類別的宣告前面,代表要產 生一個 class template (類別樣板),角 刮號中由 class 或 typename 接續一個標幟 名 T ,稱為參數型態;用來代表使用者 可自行定義的型態 在此類別樣板的成員宣告中,接著即以 型別參數 T 來指定其內容的型別。
23
Stack.h (2 of 3) 資料成員 stackPtr 是一個指標, 指向一個 T 的陣列 如果將成員函式提到類別宣告 外部來實作,則每個函式都在 跟在一個樣板標頭的後面。 注意!!在此, Stack 是被實作為一個 類別樣本,一般化樣板的類別名稱為 Stack ,而非
24
Stack.h (3 of 3)
25
Note ★ ★ ★ ★ ★ Software Engineering Observation 14.1 ◦ Most C++ compilers require the complete definition of a template to appear in the client source-code file that uses the template. ◦ For class templates, this means that the member functions are also defined in the header file. ◦ 請注意!樣板的運作模式是,是由編譯器根據樣板的定義,以及使 用者所指定的型別,先自動產生出對應的程式碼後再行編譯。編譯 的過程與一般的類別不同(個別編譯後進行連結),因此大部分的 C++ 編譯器會要求使用樣板的程式檔要包含完整的樣板定義,所以 我們會把樣板的完整定義(包含成員函式的實作)一律寫在.h 檔中 ,這和一般我們設計類別時,要求宣告和實作要分開的情況不同。
26
fig14_03.cpp (1 of 3) 樣板類別定義的所有內容在此 標頭檔中 產生特殊化樣板類別( class- template specialization ), Stack 。 編譯器會將型態 double 與參數型 態 T 連結
27
fig14_03.cpp (2 of 3) 產生特殊化樣板類別( class- template specialization ), Stack 。 編譯器會將型態 int 與參數型態 T 連結
28
fig14_03.cpp (3 of 3) 註:在本例中,編譯器實際上將套用型別參數,分別產生兩個 Stack 的 副本用來處理 double 與 int 的元素資料,就效能來看,其和使用者自己 把 Stack 重寫兩次的結果是一樣的。不過,使用樣板的好處主要是在增 加程式碼的可再利用率,避免程式碼的重複撰寫。
29
fig14_04.cpp (1 of 3) 在本例中,主要示範如何建立一個函式樣 板,並以 Stack 的物件作為其參數 代表使用參數型態 T ,用來代 表 Stack 中的儲存資料型別 注意「 += 」運算子的使用;如果 T 是一個自訂類 別的話,則如果要在其物件進行「 += 」的運算, 代表此類別必須要 _______________________
30
fig14_04.cpp (2 of 3)
31
14.5 Nontype Parameters and Default Types for Class Templates Nontype template parameters ◦ Can have default arguments ◦ Are treated as const ◦ Example Template header: template In the constructor, we can use nontype paramemter stackPtr = new T[ elements ]; Declaration: Stack salesFigures;
32
14.5 Nontype Parameters and Default Types for Class Templates Type parameters can have default arguments too ◦ Example Template header: template Declaration: Stack<> jobDescriptions;
33
Exercise Use the concept of template to implement Queue. What is a queue? ◦ First-In-First-Out (FIFO) Push (A) Push (B) Push (C) Push (D) Pop (E) Pop () Which one is deleted by the function Pop()? A B C D E Add a new item on the rear of queue. Get the item at the front of queue and remove it from the queue. rearfront
34
An Implementation of Queue Assume integer elements are considered. class Queue { public: Queue (int = 10); //Default constructor ~ Queue(); bool push (int); //Push an integer into the queue; return true if successful bool pop (int &); //Pop an integer from the queue; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int front, rear; //initialized to 0 int *queuePtr; };
35
Implementing Queue Using Array Suppose the length of array is n. ◦ This approach runs into a problem when rear equals to n- 1. ◦ Shifting all elements to the left? Time-consuming. AABABC rear BC front BCD rearfront
36
Circular Queue A BC D 01234567 ABCD 0 1 23 4 5 67 rear front rear front Push (A) Push (B) Push (C) Push (D) Pop () Push (E) Push (F) Push (G) Push (H) Push (I) rear front E FG H I E rear F G HI
37
0 1 23 4 5 67 front 0 1 23 4 5 67 rear A BC D E FG H How do know whether the queue is empty or full?
38
An Implementation of Queue Assume integer elements are considered. class Queue { public: Queue (int = 10); //Default constructor ~ Queue(); bool push (int); //Push an integer into the queue; return true if successful bool pop (int &); //Pop an integer from the queue; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int front, rear; //initialized to -1; always maintain the next index to pop int *queuePtr; }; Queue (int s) : size( (s > 0)? s : 10 ), front(0), rear(0) { queuePtr = new int[size]; } ~Queue() { delete [] queuePtr; } bool Queue::push (int pushValue) { if (!isFull()) { rear = (rear+1) % size; queuePtr[rear] = pushValue; return true; } return false; } bool Queue:: pop (int &popValue) { if (!isEmpty()) { front = (front+1) % size; popValue = queuePtr[front]; return true; } return false; } bool Queue ::isFull () const { return ((rear+1) % size == front); } bool Queue ::isEmpty () const { return (rear == front); }
39
Implementing Queue Using Template #ifndef QUEUE_H #define QUEUE_H template class Queue { public: Queue(int = 10); ~Queue(); bool push( const T & ); bool pop( T & ); bool isFull() const; bool isEmpty() const; private: int size; int front, rear; T *queuePtr; } ; 1. 2. 3. 4.
40
Implementing Queue Using Template Assume integer elements are considered. class Queue { public: Queue (int = 10); //Default constructor ~ Queue(); bool push (int); //Push an integer into the queue; return true if successful bool pop (int &); //Pop an integer from the queue; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int front, rear; //initialized to -1; always maintain the next index to pop int *queuePtr; }; template Queue :: Queue (int s) : size( (s > 0)? s : 10 ), front(0), rear(0) { queuePtr = new T[size]; } template Queue :: ~Queue() { delete [] queuePtr; } template bool Queue:: push ( const T &pushValue ) { if (!isFull()) { rear = (rear+1) % size; queuePtr[rear] = pushValue; return true; } return false; } 5. 6. 7. 8. 9. 10. 11.12.
41
Implementing Queue Using Template class Queue { public: Queue (int = 10); //Default constructor ~ Queue(); bool push (int); //Push an integer into the queue; return true if successful bool pop (int &); //Pop an integer from the queue; return true if successful bool isEmpty() const; //Return true if the array is empty bool isFull() const; //Return true if the array is full private: int size; //array size int front, rear; //initialized to -1; always maintain the next index to pop int *queuePtr; }; template bool Queue :: pop ( T &popValue ) { if (!isEmpty()) { front = (front+1) % size; popValue = queuePtr[front]; return true; } return false; } template bool Queue :: isFull () const { return ((rear+1) % size == front); } template bool Queue :: isEmpty () const { return (rear == front); } #endif 13. 17. 16. 14. 19. 18. 15.
42
7.11 Introduction to C++ Standard Library Class Template vector C-style pointer-based arrays ◦ Have great potential for errors and several shortcomings C++ does not check whether subscripts fall outside the range of the array Two arrays cannot be meaningfully compared with equality or relational operators One array cannot be assigned to another using the assignment operators
43
7.11 Introduction to C++ Standard Library Class Template vector Class template vector ◦ Available to anyone building applications with C++ ◦ Can be defined to store any data type Specified between angle brackets in vector All elements in a vector are set to 0 by default ◦ Member function size obtains size of array Number of elements as a value of type size_t ◦ vector objects can be compared using equality and relational operators. ◦ Assignment operator can be used for assigning vector s. ◦ Individual elements can be accessed with square brackets.
44
7.11 Introduction to C++ Standard Library Class Template vector vector member function at ◦ Provides access to individual elements ◦ Performs bounds checking Throws an exception when specified index is invalid Accessing with square brackets does not perform bounds checking
45
fig07_26.cpp (1 of 6) 類別樣板 vector 將儲 存 int 元素 vector 為特殊化類別樣板, 儲存資料型別已經明確定義 vector 類別樣板內含成員 變數 size ,用來記錄當中 的元素個數 注意!使用 vector 類別樣 板前必須引入 標 頭檔
46
fig07_26.cpp (2 of 6) 你可以比較兩個 vector 物件是否相等。 因為該類別 _______ 了「 != 」運算子 你也可以從一個 vector 物件建立它的副 本,或作兩個物件的指定。因為該類別 提供了 _______ 以及 _________
47
fig07_26.cpp (3 of 6) vector 多載註標運算子,用來存取某一 個元素的內容;然而註標運算子的多載 函式並未提供範圍的檢查 函式 at() 也同樣可以用來存取某一個元 素的內容;然而此函式提供範圍的檢查
48
fig07_26.cpp (4 of 6)
49
fig07_26.cpp (5 of 6) Execution Result
50
fig07_26.cpp (6 of 6) Execution Result 超出索引範圍, at() 將強制終止程 式。
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.