第十一章 (上篇) 函數樣板(Function Template) 與 類別樣板(Class Template)

Slides:



Advertisements
Similar presentations
C++语言程序设计教程 第5章 构造数据类型 第6章 C++程序的结构.
Advertisements

第一單元 建立java 程式.
第九讲 类与对象 (I)面向对象基础.
程設一.
程設一.
复习与总结.
Chap 18 類別與物件 夫有土者,有大物也。有大物者,不可以物。 物而不物,故能物物。 明乎物物者之非物也,豈獨治天下百姓而已哉!
4.1 概述 4.2 类与对象的实现 4.3 对象的初始化和析构 4.4 类的包含 4.5 类模板
Derived Class 前言 衍生類別的定義 單一繼承 public, protected, 和 privated 基底類別
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
Scope & Lifetime 前言 Local Scope Global Functions & Objects
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
哈夫曼编码.
刘胥影 东南大学计算机学院 面向对象程序设计1 2010~2011第3学期 刘胥影 东南大学计算机学院.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
程序设计期末复习 黎金宁
第三章 C++中的C 面向对象程序设计(C++).
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
類別(class) 類別class與物件object.
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全.
第四章 小技巧.
类类型 C++支持的内置类型和操作,如 int i=10; i=i%6; i=i+4;
service-side: throw Exceptions client-side: try-and-catch
第十章 模板 丘志杰 电子科技大学 计算机学院 软件学院.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
第一單元 建立java 程式.
10 多載函數 10.1 多載概論 多載一般函數 多載成員函數 10-3
Classes (2) Lecture 7.
第十三讲 文件流与 输出输入重载.
二叉树的遍历.
常宝宝 北京大学计算机科学与技术系 数据结构(三) 常宝宝 北京大学计算机科学与技术系
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
潘爱民 C++ Overview 潘爱民
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第10讲 构造函数和析构函数 构造函数 析构函数 This 指针.
保留字與識別字.
第二章 Java基本语法 讲师:复凡.
第四章 栈和队列 栈 ( Stack ) 队列 ( Queue ) 优先队列 (Priority Queue) 小结.
樣版.
第三章 数据抽象.
C++大学基础教程 第10章 运算符重载 北京科技大学 2019/5/7 北京科技大学.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++程序设计 吉林大学计算机科学与技术(软件)学院.
C++程序设计基础 主讲人:谢昕 华东交通大学信息工程学院 第十~十二讲 多态性和虚函数 2005年春季学期.
第二章 基本数据类型 ——数据的表示.
第九章 物件導向-進階.
第1章 C++面向对象程序设计要点 1.1 函数和函数参数 1.2 输入输出   1.3 类 1.4 抽象类型和模板.
第 9 章 建構函式與解構函式.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
挑戰C++程式語言 ──第9章 函數.
#include <iostream.h>
第四章 函数 丘志杰 电子科技大学 计算机学院 软件学院.
第二章 Java基本语法 讲师:复凡.
第7章 模板 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
Class 2005/05/25.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
第三章 高级函数特性.
對於成員(member)存取權的限制 成員的資料被毫無限制的存取,任誰都可以指定任意值給成員,Java語言為了防止這種現象的產生,規定:有一種成員的資料不能任由類別外部的任何人隨意存取。
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
C++程序语言设计 Chapter 14: Templates.
資料!你家住哪裏? --談指標 綠園.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
第十二章 C与C C转入C++时不需改变的内容 12.2 C转入C++的一些与类无关的 新特性
方法(Method) 函數.
Presentation transcript:

第十一章 (上篇) 函數樣板(Function Template) 與 類別樣板(Class Template) 建立通用函數(Generic Functions) & 通用類別(Generic Classes) - Code Reuse 的另一種發揮 - 煩人的事 經歷一次就夠了

為何需要通用函數? 取名困難 int abs(int x) { return (x>0)?x:-x; } 不好記 int fabs(float x) { return (x>0)?x:-x; } int cabs(complex x) { return (x>0)?x:-x; }

為何需要通用函數? [overloading] 同樣的東西 int abs(int x) { return (x>0)?x:-x; } 為何要寫三次? int abs(int x) { return (x>0)?x:-x; } int abs(float x) { return (x>0)?x:-x; } int abs(complex x) { return (x>0)?x:-x; }

利用函數樣板來實現通用函數的理想 當有一組函數: (1) 內容一樣 (2) 參數資料型態不同 把資料型態當 參數傳過去 建立函數模板 int abs(int x) { return (x>0)?x:-x; } 當有一組函數: (1) 內容一樣 (2) 參數資料型態不同 int abs(float x) { return (x>0)?x:-x; } int abs(complex x) { return (x>0)?x:-x; } 把資料型態當 參數傳過去 建立函數模板

函數樣板的定義方式 int abs( int x) { 2 return (x>0)?x:-x; 3 } T T 保留字 函數模板 3 } T T 保留字 函數模板 1 template <class T> 2 T abs( T x) { 3 return (x>0)?x:-x; 4 }

函數樣板的使用 1 template <class T> 2 T abs( T x) { 3 return (x>0)?x:-x; } void main() { int a = 3; float b=-2.83; complex c(-5, -2) ; cout << abs(a) << endl ; cout << abs(b) << endl ; cout << abs(c) << endl ;

編譯器到底做了甚麼? 1 template <class T> 2 T abs( T x) { 3 return (x>0)?x:-x; } void main() { int a = 3; float b=-2.83; complex c(-5, -2) ; cout << abs(a) << endl ; cout << abs(b) << endl ; cout << abs(c) << endl ; int abs(int x) { return (x>0)?x:-x; } float abs(float x) { return (x>0)?x:-x; } 自動產生 complex abs(complex x) { return (x>0)?x:-x; } 自動產生

另一種函數樣板的使用 1 template <class T> 2 T abs( T x) { 3 return (x>0)?x:-x; } void main() { // int a = 3; float b=-2.83; complex c(-5, -2) ; cout << abs(3) << endl ; cout << abs(2.83) << endl ; // T=?? cout << abs(complex(-5, -2)) << endl ;

EX: 通用的swap() void swap(int& x, int& y) { int temp=x; x=y; y=temp;} void swap(double& x, double& y) { … } void swap(frac& x, frac& y) { … } void main( ) { int a = 5, b =3 ; double d1=3.4, d2=5.6 ; frac f1(5, 3), f2(6, 7) ; swap(a, b); swap(d1, d2); swap(f1, f2) ; }

通用的swap() template <class T> void swap1(T& x, T& y) { T temp=x; x=y; y=temp;} void main( ) { int a = 5, b =3 ; double d1=3.4, d2=5.6 ; swap1(a,b); cout<<a<<b<<endl; swap1(d1, d2); cout<<d1<<d2<<endl; }

EX: 通用的print_arr() void main( ) { int x[] = {1,2,3} ; float y[] = {1.1,2.2,3.3}; complex z[3] ={{1,1,},{2,2},{3,3}}; print_arr(x, 3) ; // 印出 1 2 3 print_arr(y, 3); // 印出 1.1 2.2 3.3 print_arr(z, 3) ; // 印出 1+1i 2+2i 3+3i } Q: 編譯器到底做了甚麼?

EX: 通用的ROR() void ROR(int a[], int size) {…} a[size-1] a[0]

EX: 通用的max(a,b) [寫法一] template <class T> T max(T a, T b) { return (a>b)?a:b; } void main() { cout << max(5, 3) << endl; cout << max(-3.14, 5.2) <<endl; cout << max(2.3, 5) <<endl ; //可乎? } 否

EX: max(a,b) [寫法二] template <class T1, class T2> T1 max(T1 a, T2 b) { return (a>b)?a:b; } void main() { cout << max(5, 3) << endl; cout << max(-3.14, 5.2) <<endl; cout << max(5, 7.8) <<endl ; //印出啥? }

觀察 使用Function Template只是少打字而已,可執行檔的大小並未減低。 為甚麼不使用Macro就好了?

[Note1]: template <class T> 的scope T abs(T x) { …. } T max(T a, T b) { ….. 樣板一 template <class T> 樣板二

[Note2]: 換不換行沒關係 template <class T> T abs(T x) { …. }

[Note3]:樣板參數的宣告的變化 // type name 隨你取 template <class Atype> Atype abs(Atype x) { …. } // class 可用typename取代 template <typename Atype> Atype abs(Atype x) { …. }

[Note4]: template <….>與函數定義間不可有任何指令 template <class Atype> const int x=18 ; // error Atype abs(Atype x) { …. }

[Note5]: 函數樣板與樣板函數 template <class T> 函數樣板 int abs( T x) { return (x>0)?x:-x; } 函數樣板 (Function Template) float abs(float x) { return (x>0)?x:-x; } frac abs(frac x) { return (x>0)?x:-x; } int abs(int x) { return (x>0)?x:-x; } 樣板函數 (Template Function) 產生函數(Generated Function)

函數呼叫規則 (Rules of Function Invocation) (一) template <class T> T add(T x, T y) { cout << “F1”; return x+y ; } int add(int x, int y) { cout << “F2 “; return x+y ;} void main() { cout << add(3,8) << endl ; } Result: Rules: F2

函數呼叫規則(二) template <class T1, class T2> T1 add(T1 x, T2 y) { cout << “F1”; return x+y ; } int add(int x, int y) { cout << “F2 “; return x+y ;} void main() { cout << add(3.5, 8) << endl ; } Result: Rules: F1

函數呼叫規則(三) template <class T> T add(T x, T y) { cout << “F1”; return x+y ; } template <class T1, class T2> T1 add(T1 x, T2 y) { cout << “F2 “; return x+y ;} void main() { cout << add(3,8) << endl ; } Result: Rules: error

[作業] 通用的find與sort int find(int a[], int size, int x) { …… } void sort( int a[], int size) { void main() { int a[50]; complex c[50]; frac f[50] ; // 應用sort()與find()在int[], complex[]與frac[]

通用的find void main() template <class T> int find(T a[], int size, T x) { int i=0; int result; for(i=0;i<size;i++) { if(x==a[i]) result=i; break; } } return result;} void main() { int a[5]={1,2,3,4,5}; float b[5]={1.1,2.2,3.3,4.4,5.5}; cout<<find(a,5,3)<<endl; cout<<find(b,5,(float)4.4)<<endl; }

T 的責任 class complex { copy constructor operator= } ; template <class T> T add(T x, T y) { T z = x+y ; return z ; } void main() { complex c1, c2 ; ….. cout << add(c1, c2) ; class list { copy constructor operator= operator+ operator<< } ;

為何需要通用類別 (Generic Class) // 你厭倦了為不同的type寫class嗎? class char_stack{ char data[10] ;....} ; class int_stack {int data[10]; ...} ; class complex_stack{complex data[10]; ....}; ......  我需要通用的stack類別

類別樣板(Class Template) template <class T> T T T class stack { private: int data[10] ; int top, size ; public: stack():top(-1),size(10) {} stack(const stack& s) { for (int i=0 ; i<10; i++) data[i] = s.data[i] ; top = s.top ; } int pop( ) { return data[top--] ; } void push( int x) { data[++top] = x ; } void print() { for(int i=0;i<=top;i++) {cout<<data[i]<<endl;} } ; template <class T> T T T

類別樣板的使用 Q1: s1, s2 and s3 的資料型態為何? Q2: 編譯時會發生 甚麼事? void main( ) { stack<int> s1; s1.push(5) ; …….. stack<float> s2 ; s2.push(3.14) ; statck<complex> s3 ; ….. stack<int> s2(s1) ; } Q1: s1, s2 and s3 的資料型態為何? Q2: 編譯時會發生 甚麼事?

定義在類別樣板外的成員函數 回想 class stack { private: int data[10] ; int top, size ; public: stack():top(-1),size(10) {} int pop( ) { return data[top--] ; } void push( int x) ; } ; void stack::push( int x) { data[++top] = x ; }

定義在類別樣板外的成員函數 正確 版本 template <class T> class stack { ……. void push(T x) ; //如何定義push() } ; void stack::push(T x) { data[++top] = x; } void stack<T>::push(T x) {data[++top] = x ; } 正確 版本 template <class T> void stack<T>::push(T x) {data[++top] = x ; }

EX: 重新定義 stack template template <class T> class stack { private: T data[10] ; int top, size ; public: stack(); T pop( ); void push(T x); } ;

測試stack template void main() { stack<int> s1 ; for (int i = 0 ; i<5; i++) s1.push(i) ; s1.print() ; stack<char> s2 ; for (i = 0 ; i<5; i++) s2.push(‘A’+i) ; s2.print() ; }

More on Class Template template <class T> 實際測試一次 class stack { private: T data[10] ; int top, size ; public: stack(); stack(const stack& s) {…} …… } ; 實際測試一次 template <class T> stack<T>::stack(const stack<T>& s) { for (int i=0 ; i<10; i++) data[i] = s.data[i] ; top = s.top ; }

EX: 通用二維座標 p1.print(); p2.print(); // 改寫為class template 使main中的程式碼可以運作 template <class T> class point { T x, y ; public: point(T a, T b) { x = a; y=b;} void print() { cout << x << “ ”<< y ; } } ; void main() { point<double> p1(3.5, 6.3) ; point<int> p2(3, 9) ; p1.print(); p2.print(); }

EX: 再度測試stack template void main() { stack<int> s1 ; for (int i = 0 ; i<5; i++) s1.push(i) ; s1.print() ; stack<complex> s2 ; for (int i = 0 ; i<5; i++) s2.push(complex(i, i)) ; s2.print() ; stack<stack<int> > ss ; // 注意 > >之間要有空格 ss.push(s1) ; ss.push(s1) ; ss.print() ; }

不過載operator<< template <class T> void stack { T data[10]; int top, size; ... void print() { for (int i = 0 ; i<=top; i++) { cout << data[i] << “ “ ; // 根本不work! } void main() { stack<complex> s; ..... s.print() ; } (4,2) data[1] (5,3) data[0]

過載 operator<<() class complex { double a, b ; public: ...... void print() {cout << a << “+” << b<<“i”; } } ; void main() { complex c(5,3); c.print() ; cout << c ; // 可以這樣嗎? // 轉成 operator<<(cout, c); }

過載 operator<<() class complex { double a, b ; public: ...... friend ostream& operator<<(ostream& out, const complex& c) ; } ; ostream& operator<<(ostream& out, const complex& c) { out << c.a << “+” << c.b<<“i”; //做與print()相同的事 return out ; } void main() {complex c(5,3); cout << c <<endl ;} operator<<(cout, c)

結論 每個class都應該寫operator<< 自我練習 只要將原先的print()或show()改寫即可 complex, list, stack, frac

EX: 測試stack template void main() { stack<int> s1 ; for (int i = 0 ; i<5; i++) s1.push(i) ; cout << s1 << endl ; stack<complex> s2 ; for (int i = 0 ; i<5; i++) s2.push(complex(i, i)) ; cout << s2 << endl ; stack<stack<int>> ss ; ss.push(s1) ; ss.push(s1) ; cout << ss << endl ; } Note that Template Sort Operator<<

Template的參數 template <class T, int n> class stack { T data[n] ; …... } ; void main( ) { stack<int,50> s1 ; stack<int,30> s2 ; stack<float, 40> s3 ; stack<float, 70> s4 } What’s the data type of s1, s2, s3 and s4? 缺點:

練習 課本 11-11 ~ 11-16

作業(or 自我練習) complex> input a 5 3 complex> input b -1 2 -1 2 complex> eval (a+b)*(a-b)/(2.5*a) ??????

自我挑戰: 完成以下SortedList void main() { SortedList<int> L1; L1.insert(10); L1.insert(25) ; L1.insert(13); L1.insert( 20) ; cout << L1 << endl ; // 10 13 20 25 SortedList<Frac> L2; L2.insert(Frac(3,5)); L2.insert( Frac(2,5)) ; L2.insert(Frac(1,13)); L2.insert(Frac(4,20)) ; cout << L2 << endl ; // 1/13 1/5 2/5 3/5 SortedList<SortedList<int>> LL ; LL.insert(L1); LL.insert(L1); cout << LL <<endl ; }