• 沒有找到結果。

void main() {

N/A
N/A
Protected

Academic year: 2022

Share "void main() {"

Copied!
45
0
0

加載中.... (立即查看全文)

全文

(1)

第十一章 (上篇)

函數樣板(Function Template) 與 類別樣板(Class Template)

„ 建立通用函數(Generic Functions) &

通用類別(Generic Classes) - Code Reuse 的另一種發揮

- 煩人的事 經歷一次就夠了

(2)

為何需要通用函數?

int abs(int x) { return (x>0)?x:-x; }

int abs(int x) { return (x>0)?x:-x; } 取名困難 取名困難不好記 不好記

int fabs(float x) { return (x>0)?x:-x; } int fabs(float x) { return (x>0)?x:-x; }

int cabs(complex x) { return (x>0)?x:-x; } int cabs(complex x) { return (x>0)?x:-x; }

(3)

為何需要通用函數?

[overloading]

同樣的東西

為何要寫三次?

[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(float x) { return (x>0)?x:-x; }

int abs(complex x) { return (x>0)?x:-x; } int abs(complex x) { return (x>0)?x:-x; }

(4)

利用函數樣板來實現通用函數 的理想

當有一組函數:

(1) 內容一樣

(2) 參數資料型態不同 當有一組函數:

(1) 內容一樣

(2) 參數資料型態不同

把資料型態當 參數傳過去 把資料型態當 參數傳過去

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(float x) { return (x>0)?x:-x; }

int abs(complex x) { return (x>0)?x:-x; } int abs(complex x) { return (x>0)?x:-x; }

(5)

函數樣板的定義方式

1 int abs( int x) {

2 return (x>0)?x:-x;

3 }

1 int abs( int x) {

2 return (x>0)?x:-x;

3 }

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;

4 }

函數模板函數模板 保留字

T

(6)

函數樣板的使用

1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(a) << endl ;

8 cout << abs(b) << endl ; 9 cout << abs(c) << endl ; 1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(a) << endl ;

8 cout << abs(b) << endl ; 9 cout << abs(c) << endl ;

(7)

編譯器到底做了甚麼?

1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(a) << endl ;

8 cout << abs(b) << endl ; 9 cout << abs(c) << endl ; 10 }

1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(a) << endl ;

8 cout << abs(b) << endl ; 9 cout << abs(c) << endl ; 10 }

int abs(int x) { return (x>0)?x:-x; } int abs(int x) { return (x>0)?x:-x; }

float abs(float x) { return (x>0)?x:-x; } 自動產生 float abs(float x) { return (x>0)?x:-x; }

自動產生

(8)

另一種函數樣板的使用

1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 // int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(3) << endl ;

8 cout << abs(2.83) << endl ; // T=??

9 cout << abs(complex(-5, -2)) << endl ; 1 template <class T>

2 T abs( T x) {

3 return (x>0)?x:-x;

4 }

5 void main() {

6 // int a = 3; float b=-2.83; complex c(-5, -2) ; 7 cout << abs(3) << endl ;

8 cout << abs(2.83) << endl ; // T=??

9 cout << abs(complex(-5, -2)) << endl ;

(9)

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) ; }

(10)

通用的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;

(11)

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: 編譯器到底做了甚麼?

Q: 編譯器到底做了甚麼?

(12)

EX: 通用的ROR()

void ROR(int a[], int size) {…}

a[0] a[size-1]

(13)

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 ; //可乎?

}

(14)

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 ; //印出啥?

}

(15)

觀察

„ 使用Function Template只是少打字而 已,可執行檔的大小並未減低。

„ 為甚麼不使用Macro就好了?

(16)

[Note1]: template <class T>

的scope

template <class T>

T abs(T x) {

….

}

T max(T a, T b) {

…..

}

template <class T>

T abs(T x) {

….

}

T max(T a, T b) {

…..

template <class T>

樣板一

樣板二

(17)

[Note2]: 換不換行沒關係

template <class T>

T abs(T x) {

….

}

template <class T>

T abs(T x) {

….

}

template <class T> T abs(T x) {

….

}

template <class T> T abs(T x) {

….

}

(18)

[Note3]:樣板參數的宣告的變 化

// type name 隨你取

template <class Atype>

Atype abs(Atype x) {

….

}

// type name 隨你取

template <class Atype>

Atype abs(Atype x) {

….

}

// class 可用typename取代

template <typename Atype>

Atype abs(Atype x) {

// class 可用typename取代

template <typename Atype>

Atype abs(Atype x) {

(19)

[Note4]: template <….>與函 數定義間不可有任何指令

template <class Atype>

const int x=18 ; // error Atype abs(Atype x) {

….

}

template <class Atype>

const int x=18 ; // error Atype abs(Atype x) {

….

}

(20)

[Note5]: 函數樣板與樣板函數

template <class T>

int abs( T x) {

return (x>0)?x:-x;

}

template <class T>

int abs( T x) {

return (x>0)?x:-x;

}

int abs(int x) {

return (x>0)?x:-x;

}

int abs(int x) {

return (x>0)?x:-x;

}

frac abs(frac x) { return (x>0)?x:-x;

}

frac abs(frac x) { return (x>0)?x:-x;

} float abs(float x) {

return (x>0)?x:-x;

}

float abs(float x) { return (x>0)?x:-x;

}

函數樣板

(Function Template)

(21)

函數呼叫規則 (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 ; }

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:

(22)

函數呼叫規則(二)

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 ; }

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:

Result:

(23)

函數呼叫規則(三)

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 ; }

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:

Result:

Rules:

(24)

[作業] 通用的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[]與

(25)

通用的find

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; }

void main() void main()

{ { intint a[5]={1,2,3,4,5};a[5]={1,2,3,4,5};

float b[5]={1.1,2.2,3.3,4.4,5.5};

float b[5]={1.1,2.2,3.3,4.4,5.5};

coutcout<<find(a,5,3)<<<<find(a,5,3)<<endl;endl;

coutcout<<find(b,5,(float)4.4)<<<find(b,5,(float)4.4)<

<<endlendl;; }}

(26)

T 的責任

template <class T>

T add(T x, T y) { T z = x+y ; return z ; }void main() {

complex c1, c2 ;

…..

cout << add(c1, c2) ; }

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 complex {

copy constructor operator=

operator+

operator<<

} ;

class complex {

copy constructor operator=

operator+

operator<<

} ;

class list {

copy constructor operator=

operator+

operator<<

class list {

copy constructor operator=

operator+

(27)

為何需要通用類別 (Generic Class)

// 你厭倦了為不同的type寫class嗎?

class char_stack{ char data[10] ;....} ; class int_stack {int data[10]; ...} ;

class complex_stack{complex data[10]; ....};

...

Æ 我需要通用的stack類別

(28)

類別樣板(Class Template)

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 ; } 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 ; } T

T

template <class T>

(29)

類別樣板的使用

void main( ) {

stack<int> s1;

s1.push(5) ; ……..

stack<float> s2 ; s2.push(3.14) ;

statck<complex> s3 ;

…..

stack<int> s2(s1) ; }

void main( ) {

stack<int> s1;

s1.push(5) ; ……..

stack<float> s2 ; s2.push(3.14) ;

statck<complex> s3 ;

…..

stack<int> s2(s1) ; }

Q2: 編譯時會發生 Q2: 編譯時會發生甚麼事?

甚麼事?

Q1: s1, s2 and s3

的資料型態為何?

Q1: s1, s2 and s3

的資料型態為何?

(30)

定義在類別樣板外的成員函數

class stack { private:

int data[10] ; int top, size ; public:

stack():top(-1),size(10) {}

int pop( ) { return data[top--] ; } void push( int x) ;

} ;

class stack { private:

int data[10] ; int top, size ; public:

stack():top(-1),size(10) {}

int pop( ) { return data[top--] ; } void push( int x) ;

} ;

回想

(31)

定義在類別樣板外的成員函數

template <class T>

class stack {

…….void push(T x) ; //如何定義push() } ;

template <class T>

class stack {

…….void push(T x) ; //如何定義push() } ;

template <class T>

template <class T>

void stack<T>::push(T x) {data[++top] = x ; } void stack<T>::push(T x) {data[++top] = x ; }

void stack::push(T x) { data[++top] = x; } void stack::push(T x) { data[++top] = x; }

正確

(32)

EX: 重新定義 stack template

template <class T>

class stack { private:

T data[10] ; int top, size ; public:

stack();

T pop( );

void push(T x);

template <class T>

class stack { private:

T data[10] ; int top, size ; public:

stack();

T pop( );

void push(T x);

(33)

測試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) ;

(34)

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>

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) {

實際測試一次 實際測試一次

(35)

EX: 通用二維座標

// 改寫為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();

(36)

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 ; // 注意 > >之間要有

空格

(37)

不過載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() ; } (5,3) (4,2)

data[0]

data[1]

(38)

過載 operator<<()

class complex { double a, b ; public:

...

void print() {cout << a << “+” << b<<“i”; } } ;

void main() {

complex c(5,3); c.print() ;

cout << c ; // 可以這樣嗎?

(39)

過載 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)operator<<(cout, c)

(40)

結論

„ 每個class都應該寫operator<<

„ 只要將原先的print()或show()改寫即可

„ 自我練習

„ complex, list, stack, frac

(41)

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

1. Template

2. Sort

Operator<<

(42)

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 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?

What’s the data type of s1, s2, s3 and s4?

缺點:缺點:

(43)

練習

„ 課本 11-11 ~ 11-16

(44)

作業(or 自我練習)

complex> input a 5 3

complex> input b -1 2

complex> eval (a+b)*(a-b)/(2.5*a)

??????

(45)

自我挑戰: 完成以下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 ; }

參考文獻

相關文件

第 1 次招考 108.7.3(三) 下午 17:00 時前公告於本校網站. (二)錄取時僅以電話通知,不另寄發成績通知;若需成績通知者,請於放榜後一週內至本校人事

解難 學模式 發揮 創意 加強互.

KU 群至常奪透遊 性家希、過戲 的庭望甚學規 發以別至習則 展外人攻 -o 依擊漸 一由從性漸 這於他的變 時他們行成 期們的為使 的仍主出與 兒處意現別 童於行。人

理論,則認為人的情緒不是單純由事件本身引發的,更多是由當事人對事件的 理解或看法而引起的。ABC 理論的 A 是指誘發事件 (Activating

香港學生大多數不肯勤勤懇懇地「唸書」,其實 這也是一種靈活的特性,要利用這一點發揮學生 課堂學習的積極性。.

目標: 發揮有效的行政管理,統籌科組的行政事 務,作為上層(校長與教務主任)及下屬

OOP: organized DATA + organized code (ACTION) using classes as the basic module. action are closely coupled

普通的認股證(非特 種認股證)沒有回收