Download presentation
Presentation is loading. Please wait.
Published byἸεζάβελ Βλαβιανός Modified 5年之前
1
函式 ( function ) 的宣告(1) 當有一件事需要重複去作或過程比較複雜時,1)可以寫成函式,方便偵錯維護與往後呼叫!
int sum(int N) { int k, total=0; for ( k=1; k<=N; ++k ) total += k; return total; } 2)以 #define 的形式,來定義需要重複呼叫的程式部分! #define PI // 定義常數 #define random(n) ( rand() % n ) // 定義函式(side effect) #define new Line( ) printf(“\n”); // 簡化換行指令
2
函式 ( function ) 的宣告(2) #define PI 3.141592653 // 定義常數 建議的方式:
const : 表示變數不能再被改變(read-only) 明確的宣告常數的型態,如下的double const double PI = ; #define random(n) ( rand() % n ) // 定義函式(side effect) Ex. random( 5+1 ) ==> 原意:產生 0 ~ 5 的隨機數 事實是 ==> ( rand() % ) // 1 <= value < 5 #define subtract( a, b) a - b subtract( 10, 5 ) ==> = 5 subtract( 10, 2+3 ) ==> = 11 != 5 (a) - (b)
3
函式 ( function ) 的宣告(3) 傳回型態 函式名稱( [參數列 ,] ) { ……….. 函式主體;
傳回型態 函式名稱( [參數列 ,] ) { ……….. 函式主體; return ( [具有傳回型態的結果] ); } // 傳回型態可以是void,表示函式不必傳回任何值。 // 當函式執行過程遇到return時,便會立即結束該函式的執 行,並返回原呼叫函式的下一個指令繼續執行。需傳回 的資料則緊接著在return後面。 // 形式參數(formal argument)列可有可無!
4
函式的範例 void line() 無參數時呼叫 { for (k=0; k<10; ++k) ex. line();
printf(“*”); } void line1(int n) { for (k=0; k<n: ++k) void line2(int n, char ch) { for (k=0; k<n; ++k) printf(“%c”,ch); 無參數時呼叫 ex. line(); 一個整數型態參數 ex. line1(10); 具有兩個參數 ex. line2(10,’*’);
5
函式呼叫時的執行流程 更正確的說: 當執行到return時,便會自 程式所呼叫的函式返回! int square(int k)
void main(String args[]) { int squ; squ = square(10); System.out.println(squ); System.out.println( “The End !”); } int square(int k) { rerurn ( k*k ); } 更正確的說: 當執行到return時,便會自 程式所呼叫的函式返回!
6
變數在函式間的可視範圍 規則: 在變數宣告以下的函式,理論上均可存取該變數,但 { }會將變數隱藏起來,此時外界便無法直接存取或引用此變數!函式尋找變數的順序為:由內而外向上找。 int showData(int n) { int k; for ( k=0; k<n; ++k) printf(“%d\n”, canYouSeeMe ); // error } int canYouSeeMe=10; // exists from here. int main(void) { printf(“%d\n”, showData(10) ); printf(“%d\n”, canYouSeeMe ); // O.K. int canYouSeeMe=10; int main(void) { int canYouSeeMe=20; { int hello=99; printf(“%d\n”, sum(10) ); printf(“%d\n”, canYouSeeMe ); // blue selected printf(“hello=%d\n”, hello); } printf(“hello=%d\n”, hello); // error
7
函式的複載(overload)宣告(C++/Java)
*具有相同的函式名稱,但不同的形式參數個數 或型態。 1. 形式參數個數不同, 或 2. 參數個數相同,但具有不完全相同的型態。 *若參數完全相同,僅傳回值不同時,編譯 器也會認為這兩個函式是相同的!
8
int abs(int k); float abs(int k); 兩者相同
函式的傳回值(C++/Java) 經return傳回值並 跳離該函數 1) 具傳回值: int square(int k) { return ( k*k );} float square(float f) { return ( f*f );} int abs(int k) { if ( k>=0 ) return (k); else return (-k); } float abs(float f); double abs(double d); int abs(int k); float abs(int k); 兩者相同
9
函式參數的預設初值設定(for C++ only)
int sum(int x, int y=0, int z=1) { return ( x+y+z); } ex. k=sum(10); k=sum(10, 12); k=sum(10, 12, 9) 具初值的參數必須 靠右排列 錯誤例: int sum(int x=1, int y, int z) // k=10+0+1=11 // k= =23 // k= =31
10
函式呼叫時參數的傳遞方式(for C/C++)
傳址呼叫:(call by address) void exchange(int *x, int *y) { int temp; temp=*x; *x=*y; *y=temp; } void main() { int a=3, b=8; cout << a << b << endl; exchange(&a, &b); 傳值呼叫:(call by value) void exchange(int x, int y) { int temp; temp=x; x=y; y=temp; } void main() { int a=3, b=8; cout << a << b << endl; exchange(a, b); 給的是位址 注意&符號
11
函式呼叫時參數的傳遞方式(for C++ only)
傳參數別名:(call by reference) viod exchange(int &x, int &y) { int temp; temp=x; x=y; y=temp; } main() { int a=3, b=8; cout << a << b <<ednl; exchange(a, b); cout << a << b <<endl; 注意! 宣告的方式 Call by reference 的 reference 可以當成是 該參數的一個別名,於 是在使用這個別名時 就跟直接使用原來的 變數是一樣的!
12
函式呼叫時參數的傳遞方式(in Java)
Call by value ( primitive data type ) ex. char, int, float, double, String 2) Call by reference ( objects and array ) reference 表示該類別所在的位址、或視為此object的代名。因此經由reference對該object所代表的內容的任何改變 ,也將真正反應在該object上。 當函式在傳遞object參數時,其實是在該被呼叫函式中產生一個reference,指向原呼叫函式中對應實際參數所在的位址。
13
常用函式群簡介(for C/C++) 數學類: (math.h) 字串類: (string.h) sin(x) strlen(s)
cos(x) tan(x) atan(x) exp(x) [=ex] sqrt(x) pow(y, x) [=yx] pow10(x) [=10x] log(x) [=ln(x)] log10(x) 字串類: (string.h) strlen(s) strlwr(s) // 轉成小寫 strupr(s) // 轉成大寫 strcat(s1, s2) // s1 <= s1+s2 strcpy(s1, s2) // s1 <= s2 參數是弳度 radian
14
常用函式群簡介 ( in Java ) 要使用Java所提供的數學函式,必須引用類別 Math。 例如:
Math.E = Math.PI = Math.abs(.); Math.sin(.); …. 參考課本 8-40 頁
15
函式的遞迴呼叫(recursive call)
所謂的遞迴呼叫: 就是函式在執行過程中又呼叫到自己,而同樣自我呼叫的 方式一再的繼續下去!這種情形就稱為遞迴 (recursion). *使用時,先歸納出一再重複部分的規則. *必須有一個能終止一再呼叫的條件產生,否則就成了無盡 迴圈的狀況,將導致堆疊(stack)爆滿,程式當掉! *遞迴程式能以非常精簡的方式來巧妙的解決問題! * 一種四兩撥千斤,叫人嘆為觀止的藝術展現!
16
Recursive Demo : stack 1 || sum( 1 ) + 2 2 || 3 sum( 2 ) + 3 || : ….. ….. n-2 sum(n-3)+(n-2) || n-1 sum(n-2)+(n-1) || Save to sum(n-1)+ n n || 1+2+3+…+(n-1)+n = sum(n)
17
類別(class)的定義與宣告(1) 類別(class)可以視為自訂之新的資料型態。 其成員包含資料與方法。
資料成員或屬性(data member or property): 用以儲存描述該物件特性或相關屬性及記錄目前類別狀況的各種型態的變數。 成員函式或方法(member function or method): 處理、運算或展現資料的相關方法或函式(function)。 類別僅是描述所有物件都會具有的特性與功能;而物件(object)才是具該類別所陳述之所有功能的真正個體。
18
類別(class)的定義與宣告(2) 類別(class)可以想成是對物件的完整描述。因此在物件導向程式設計(OOP)中,我們可由外而內、經巨觀到細微的思考我們想要創造物件的概觀,再逐步的設計與實現其被期待的功能。這種想法與現實世界我們處理事務的方法是一致的。 一旦類別確立了,接下來就把它當成是新的資料型態,所以就能夠像宣告一般變數一樣的來宣告物件。 class ClassName [extends SuperClass] { class content…… } ClassName objectName; objectName = new ClassName(.); or ClassName objectName = new ClassName(.);
19
類別(class)的定義與宣告(3) // define the class Student
class Student //等同於: class Student extends Object { String name; float height, weight; int grade; void whoIAm() { System.out.println(“My name is “+name); } Student stu1; // 宣告而已,尚未真正的指向物件, // 所以對成員的引用會造成錯誤! stu1 = new Student(); // 要求配置該物件,可以引用資料成員。 Student stu2 = new Student(.); // 宣告並要求配置該物件 Student stus[] = new Student[12]; // array of Student
20
類別(class)的定義與宣告(4) Import javax.swing.JOptionPane; class Person
{ // data members, String name; float weight; float height; boolean sex; //final boolean sex; // member functions, void show() { String sex; if ( this.sex ) sex = "male"; else sex = "female"; System.out.println("I am "+name+" ("+sex+ "),\nmy height is "+height+" cm,\nmy weight is "+weight+" kgs."); }
21
類別(class)的定義與宣告(5) static void whatIsThis() // 可經由類別直接呼叫 { String msg;
msg = "String name;\n" + "float weight;\n" + "float height;\n" +"boolean sex;\n"; JOptionPane.showMessageDialog(null, msg); } public class TestClass { static public void main(String args[]) { Person.whatIsThis(); // class-level member function invoked without via object. Person person = new Person(); // declare a new object with type Person; // assigning value to object person person.name = "Jack"; person.sex = true; person.weight = 21; person.height = 117; person.show(); while (true);
22
不希望資料直接經由物件修改,所以設成private
類別(class)的定義與宣告(6) class Person { // data members, private String name // original : String name; float weight; float height; boolean sex; //final boolean sex; ………………………. public class TestClass { static public void main(String args[]) { Person.whatIsThis(); // class-level member function invoked without via object. Person person = new Person(); // declare a new object with type Person; // assigning value to object person person.sex = true; person.name = "Jack"; // Error ! person.weight = 21; person.height = 117; person.show(); } 不希望資料直接經由物件修改,所以設成private
23
類別(class)的定義與宣告(7) 建構子的目的:設定資料成員的初始值 使用this以便與形式參數的name區別
class Person { String name; float weight; float height; boolean sex; //final boolean sex; ………………………. public Person(String name, float ht, float wt, boolean male) { this.name = name; height = ht; weight = wt; sex = male; } public class TestClass { static public void main(String args[]) { Person pMing = new Person(“Casey”,128, 25, false); // 呼叫建構子 建構子的目的:設定資料成員的初始值 使用this以便與形式參數的name區別 一旦有宣告建構子在new新物件時,就必須使用適當的建構子
24
建構子可以有很多個,祇要符合overload規則即可,且不可有傳回型態
類別(class)的定義與宣告(8) class Person { String name; float weight; float height; boolean sex; //final boolean sex; ………………………. public Person() { }; // (1) 不需宣告傳回型態 public Person(String name, float ht, float wt, boolean male) // (2) { this.name = name; height = ht; weight = wt; sex = male; } …….. Person pMing = new Person(“Casey”, 128, 25, false); // 呼叫建構子(2) Person pJack = new Person(); // 呼叫建構子(1) 建構子可以有很多個,祇要符合overload規則即可,且不可有傳回型態
25
類別(class)的定義與宣告(9) 類別的繼承 使用extends Pig : 父類別,super class ColorPig :
class Pig{ String name; boolean sex; float weight; void whoIAm() { System.out.println("I am a Pig, named "+ name); } } class ColorPig extends Pig // ColorPig 繼承自Pig { String color = "black"; // new data member added, // override the method, whoIAm(), in super class Pig. 1) void whoIAm() // added somthing new: { super.whoIAm(); // invoke the method in super class System.out.println("with "+ color +" hairs."); 2) void whoIAm() // completely rewrite: { System.out.println("I am a "+ color +" Pig, named "+ name+"."); } 類別的繼承 使用extends Pig : 父類別,super class ColorPig : 子類別,derived class
26
類別(class)的定義與宣告(9) 類別的繼承 使用extends 使用例: class Pig{ String name; … }
class ColorPig extends Pig // ColorPig 繼承自Pig { String color = "black"; public ColorPig() { … } ; void whoIAm() // completely rewrite: { System.out.println("I am a "+ color +" Pig, named "+ name+"."); } 使用例: ColorPig cpig = new ColorPig(); cpig.name = “Rich”; // 父類別的資料就像是子類別的一樣 cpig.whoIAm(); 類別的繼承 使用extends
27
子類別無法存取父類別中的private資料
類別(class)的定義與宣告(10) class Pig{ private String name; … } class ColorPig extends Pig // ColorPig 繼承自Pig { String color = "black"; public ColorPig() { … } ; void whoIAm() // completely rewrite: { System.out.println("I am a "+ color +" Pig, named "+ name+"."); } 使用例: ColorPig cpig = new ColorPig(); cpig.name = “Rich”; // Error ! cpig.whoIAm(); 子類別無法存取父類別中的private資料
28
物件無法存取所屬類別中的private資料
類別(class)的定義與宣告(11) class Pig{ ……………… } class ColorPig extends Pig // ColorPig 繼承自Pig { private String color = "black"; public String getColor() // called “getter”, 有條件的取得private資料 { return( color); } public void setColor(String c) // called “setter” ,有條件的設定private資料 { color=c; } 使用例: ColorPig cpig = new ColorPig(); cpig.color = “brown”; // Error ! cpig.setColor(“brown”); // It’s O.K. ! …………………… 物件無法存取所屬類別中的private資料
Similar presentations