--- tags: C++ --- # 壹、C++ 快速入門 介紹 C++主要元素 : **型別(types)**、**變數(variables)**、**運算式(expressions)**、**述句(statement)**、**函式(functions)**。 --- 學程式最好從實作學習,在此我門**寫一個程式幫書店解決問題,儲存交易明細:** 0-201-70353-X 4 24.99 1.ISBN 2.賣出本數 3.售出單價 達成查看檔案、計算賣出數量、計算收入、平均價格。 **達成功能涵蓋** * 定義變數 * 輸出與輸入 * 使用資料結構 * 測試ISBN是否相同 * 使用迴圈處裡交易紀錄 --- ## 一、 撰寫一個簡單的 C++ 程式 ### 函式(functions) 1. 每個程式==包含一個或多個==函式 2. 其中函式一個==必命名為 main== 3. OS會呼叫 main 函式 #### 函數定義 (function definition) 四要素 1. 回傳型別(return type) 2. 函式名稱(function name) 3. 參數列(parameter list): 在括弧中、可能為空 4. 函式主體(function body): statement 構成的區塊 如下為簡單的 main ,只會進行回傳一個值的動作: ```cpp= int main() { return 0; } ``` * main 函式==必須是 int 的回傳型別==,型別 int 代表整數(integers) 型別,並且為**內建型別(built-in type)**。 * 函式主體中,return 為一個終止函式的述句,會送回一個值給函式的呼叫者,回傳值要符合函式型別。 * main 的回傳值為一個狀態指示器(status indicator),0為成功,非零意義由系統定義(通常指示發生的錯誤種類)。 :::info **型別** * 定義資料元素的內容,以及可在哪裡運算。 * 名為V的變數型別為T,通常稱為「V有型別T」或「V是一個T」。 ::: :::danger ## Can I write "void main()"? The definition ```cpp void main() { /*...*/ } ``` is not and never has been C++, nor has it even been C. >> Reference - <https://www.stroustrup.com/bs_faq2.html#void-main> [color=red] ::: :::spoiler :::success - [x] 練習 1.1 : 把程式改成回傳 -1 編譯並執行,看看你你的系統如何處裡來自main 的這種錯誤失敗指示器。 ::: --- ## 二、 認識輸出/輸入 C++包含一個可擴充性的**標準程式庫(standard library)** 提供各種功能。 ### 1. **iostream** 程式庫 * 基礎為 **istream**(代表輸入資料流) 和 **ostream**(代表輸出資料流) 兩種型別 * 資料流(stream) : 從IO裝置讀出或寫入的字元序列(a sequence of characters),指出字元隨時間循序消耗或產生。 > Reference: > [Microsoft: 什麼是資料流](https://docs.microsoft.com/zh-tw/cpp/standard-library/what-a-stream-is?view=msvc-160) #### 標準輸出輸入物件 iostream定義了四個IO物件。 | 功能 | 處理輸入 | 處理輸出 | | ---- |:--------:|:----------------:| | 型別 | istream | ostream | | 物件 | cin | cout、cerr、clog | * **cin** : 標準輸入(standard input),istream的一個物件。 * **cout** : 標準輸出(standard output),ostream的一個物件。 * **cerr** : 標準錯誤(Un-buffered standard error),ostream的一個物件,通常發出警告和錯誤訊息。 * **clog** : 標準錯誤(buffered standard error),ostream的一個物件,記錄一般資訊。 > 參考資料: > [difference between cerr and clog](https://www.tutorialspoint.com/What-is-the-difference-between-cerr-and-clog-streams-in-cplusplus) > [Microsoft: 輸出資料流](https://docs.microsoft.com/zh-tw/cpp/standard-library/output-streams?view=msvc-160) ### 2. 用到IO程式庫的一個程式 將兩個數字相加,使用 iostream 程式庫擴充 main 函式。 以下提示使用者輸入數字,並印出總和: ```cpp= #include <iostream> int main() { std::cout << "Enter two numbers:" << std::endl; int v1 = 0, v2 = 0; std::cin >> v1 >> v2 ; std::cout << v1 << " + " << v2 << " = " << v1 + v2 << std::endl; return 0; } ``` :::warning ![result](https://i.imgur.com/6msHK3n.png) **執行結果:** 輸出: Enter two numbers: 輸入: 2 6 輸出: 2 + 6 = 8 ::: #### ( 1 ). 程式第一行 ```cpp #include <iostream> ``` 告訴編譯器我們要使用 iostream 程式庫。 * 角括號 (angle bracket) 內為**標頭(header)**。 * 程式用到的機能都要引入關聯的標頭。 * #include 指示詞和標頭名稱需同一行。 * #include 指示詞需放在函式外,通常在原始碼檔案開頭。 #### ( 2 ). 寫入資料流 main 主體第一個述句執行了一個**運算式(expression)**。 * 一個運算式產生一個結果 * 由一或多個運算元(operends) 及(通常為)一個運算子(operator) 組成。 此述句之運算式使用輸出運算子 (<< 運算子) 印出內容: ```cpp std::cout << "Enter two numbers:" << std::endl; ``` << 運算子接受兩種運算元: * 左邊的運算子必須為ostream的一個物件。 * 右邊的運算子為要印出的內容。 此運算子會回傳左邊的運算元,因此可以將輸出請求串鏈起來,等同於: ```cpp (std::cout << "Enter two numbers:") << std::endl; ``` 串鏈的每個運算子都有與其左運算元相同的物件,在此例為 std::cout。使用兩個述句達成相同效果: ```cpp std::cout << "Enter two numbers:"; std::cout << std::endl; ``` 第一個運算子印出一個訊息,該訊息是一個**字串字面值(string literal)**。包在雙引號內的字元序列,會被輸出至標準輸出。 第二個運算子印出 endl,是一個特殊值,稱為 **manipulator(操作符)**。 * endl 可結束目前文字行,排清(flush) 關聯裝置緩衝區(buffer)。 * 排清緩衝區確保程式到目前產生的輸出被實際寫入輸出資料流,而非在記憶體等待寫入。 :::warning 程式設計師應總是在 debugging 過程中加入的列印述句(print statement) , 必須總是排清資料流,否則若程式當掉,輸出留在緩衝區,造成錯誤判斷。 ::: #### ( 3 ). 使用來自標準程式庫的名稱 ```cpp std::cout std::endl ``` * **命名空間(namespace)** 避免我們定義的名稱和程式庫中的名稱相同而產生衝突。 * 標準程式庫的命名空間為 std 。 * 使用程式庫,需明確指出命名空間。 * **:: 運算子** : 範疇運算子(scope operator)。 #### ( 4 ). 從資料流讀取 1. 定義**變數(variables)** 存放輸入: ```cpp int v1 = 0, v2 = 0; ``` 定義變數為整數型別int,並**初始化(initialize)** 為0。 * 初始化為創造變數的同時,賦予他指定的值。 2. 讀取輸入: ```cpp std::cin >> v1 >> v2 ; ``` 輸入運算子(**>> 運算子**) 接受兩種運算元: * 左邊的運算子接受istream的一個物件。 * 右邊的運算子為要儲存讀取內容的物件。 此運算子會回傳左邊的運算元,因此可以將輸出請求串鏈起來,等同於: ```cpp (std::cin >> v1) >> v2 ; ``` 亦可寫成: ```cpp std::cin >> v1 ; std::cin >> v2 ; ``` #### ( 5 ). 完成此程式 印出結果: ```cpp std::cout << v1 << " + " << v2 << " = " << v1 + v2 << std::endl; ``` 輸出包含: 1. 字串字面值 " + " 或 " = " 。 2. int 值 v1 、 v2。 3. 估算(evaluate) 算數運算式 v1 + v2 的結果。 程式庫定義了處理不同型別的輸出輸入運算子版本。 :::spoiler :::success - [x] 練習 1.2 : 寫一個程式在標準輸出印出 Hello, World 。 - [x] 練習 1.3 : 寫一個程式,使用乘法運算子(multiplication operator, * ) 印出乘積。 - [ ] 練習 1.4 : 改寫輸出,使用分開的述句印出各個運算元。 - [x] 練習 1.5 : 解釋下列程式片段是否合法 : ```cpp= std::cout << "The sum of " << v1; << " and " << v2; << " is " << v1 + v2 << std::endl; ``` 如果這個程式合法,他會做什麼?若不合法,那是為什麼呢?你會如何修正它? ::: ## 三、 註解 * 註解(comments) 輔助程式碼的讀者: 總結演算法的運作、標示變數用途、說明難搞的程式片段。 * 編譯器會忽略註解,故不會對效能產生影響。 * 請確保註解的正確 ### C++註解種類 1. 單行(single-line): * 以雙斜線(double slash,// ) 開始,newline 結尾。 * 可包含任何文字,包括額外的雙斜線。 * 用於單行說明。 2. 成對(paired): * /\* 開頭,*/ 結尾。 * 可含不是 */ 的任何東西,包含 newlines。 * 用於多行說明。 範例: ```cpp= #include <iostream> /* * Simple main function: * Read two numbers and write their sum */ int main() { // prompt user to enter two numbers std::cout << "Enter two numbers:" << std::endl; int v1 = 0, v2 = 0; // variables to hold the input we read std::cin >> v1 >> v2 ; // read input std::cout << v1 << " + " << v2 << " = " << v1 + v2 << std::endl; return 0; } ``` ### 成對註解不能內嵌 一個成對註解不能出現在另一個之中。 ```cpp= /* * 成對註解 /* */ 不能內嵌 * "不能內嵌" 和其他部分會被視為程式碼 */ int main() { return 0; } ``` 因此除錯時時要註解掉一個區塊的程式碼,最好在每一行開頭使用單行註解。 ```cpp= // /* // * 單行註解內的所有東西都會被忽略 // */ int main() { return 0; } ``` :::spoiler :::success - [ ] 練習 1.6 : 編譯錯誤地內嵌了註解的一個程式。 - [ ] 練習 1.7 : 指出下列述句何者是合法的(如果有的話): ```cpp std::cout << "/*"; std::cout << "*/"; std::cout << /* "*/" */; std::cout << /* "*/" /* "/*" */; ``` 預測會發生什麼後,編譯含有上述各個述句的一個程式驗證你的答案。更正你所遇到的任何錯誤。 ::: ## 四、 流程控制 述句通常上而下循序執行,程式提供各種控制述句(flow-of-control statement),讓我們寫出更複雜的執行路徑。 ### 1. while 述句 #### while 的形式 ```cpp while(condition) statement ``` #### 執行方式 反覆測試condition,若為true,則執行關聯的statement直到條件為false。 * **條件(condition)**,結果為 true 或 false 的一個運算式 #### 使用 while 執行數字1到10(包含頭尾兩個數字)的加法 ```cpp= #include <iostream> int main() { int sum = 0, num = 1; while(num <= 10) { sum += num; ++num; } std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl; return 0; } ``` :::warning ![result](https://i.imgur.com/7GO23xj.png) **執行結果:** Sum of 1 to 10 inclusive is 55 ::: while述句在此程式為: ```cpp while(num <= 10) { sum += num; ++num; } ``` 其中的條件用到小於或等於運算子(less-than-or-equal operator, **<=運算子**) 比較num和10,小於等於為true, 大於為false。若為true,則執行while主體。主體是由兩個述句所組成的一個區塊: ```cpp { sum += num; ++num; } ``` 一個區塊是包在大括號內的零或多個述句所構成,一個區塊算一個述句。 此區塊內的第一個述句使用複合指定運算子(compound assignment operator, **+=運算子**),將右邊的運算元加到並儲存於左邊,效果與一個加法運算和**指定(assignment)** 運算相同: ```cpp sum = sum + num; ``` 此區塊內的第二個述句使用前綴遞增運算子(prefix increment operator, **++運算子**),遞增運算子會加1到其運算元。其作用與 num = num + 1; 相同。 ### 2. for 述句 第二種迴圈述句,縮短程式碼。 :::spoiler :::success - [x] 練習 1.8 : 寫一個程式用 while 將 50 到 100 加總 - [x] 練習 1.9 : 使用遞減運算子 ( -- ) 寫一個 while,印出 10 遞減到 0 的數字。 - [ ] 練習 1.10 : 寫個程式提示使用者輸入兩個整數。印出由這兩個整數指定的範圍內的每個數字。 ::: #### for 的形式 每個for述句都由 標頭(header)、主體(body) 兩部分組成: * 標頭(header): 控制主體執行次數,由init-statement(初始述句)、 condition(條件)、 expression(運算式)組成。 * init-statement: 在進入for時執行,僅執行一次。 * condition: 每次跑迴圈都會被測試,為true就執行for主體。 * expression: 在for主體後執行。 * 主體(body) ```cpp for(init-statement; condition; expression) statement ``` #### 使用 for 執行數字1到10(包含頭尾兩個數字)的加法 ```cpp= #include <iostream> int main() { int sum = 0; for(int num = 1; num <= 10; ++num) sum += num; std::cout << "Sum of 1 to 10 inclusive is " << sum << std::endl; return 0; } ``` :::warning ![result](https://i.imgur.com/FNRF9Bw.png) **執行結果:** Sum of 1 to 10 inclusive is 55 ::: 這個 for 的執行流程 : 1. 創建 num 並初始化它為 1。 2. 測試 num 是否小於等於 10,為true執行for主體,false 跳出迴圈。 3. 遞增 num。 4. 重複 2. 的測試。 ```flow st=>start: 進入 for e=>end: 跳出 for op=>operation: int num = 1; cond=>condition: num <= 10; op2=>operation: sum += num; op3=>operation: ++num st->op->cond cond(yes,right)->op2(right)->op3(right)->cond cond(no)->e ``` :::spoiler :::success - [x] 練習 1.11 : 下列 for 迴圈會做什麼? sum 最終的值會是什麼 ? ```cpp= int sum = 0; for (int i = -100; i <= 100; ++i) sum += i; ``` - [ ] 練習 1.12 : 使用 for 改寫 練習 1.8 和 練習 1.9。 - [x] 練習 1.13 : 對照比較使用 for 與使用 while 的迴圈各有什麼優缺點。 ::: ### 3. 讀取未知數量的輸入 持續讀取數字並加總,直到沒有輸入讀取為止。 ```cpp= #include <iostream> int main() { int sum = 0, num = 0; //持續讀取直到讀到檔案結尾(EOF, end-of-file)為止 while(std::cin >> num) sum += num; std::cout << "total is : "<< sum << std::endl; return 0; } ``` :::warning ![result](https://i.imgur.com/aHJYW39.png) **執行結果:** 輸入: 1 2 4 輸出: total is : 7 ::: 我們在while的條件內讀取資料: ```cpp while(std::cin >> num) ``` 估算這個while條件會執行運算式: ```cpp std::cin >> num ``` 此運算式從標準輸入讀取下一個數字,並將數字儲存在num。輸入運算子回傳它的左運算元(在此為 std::cin),因此,這個條件會測試std::cin。 *[輸入運算子]: >> 運算子 使用istream作為條件,等同測試資料流(stream)的狀態。 若資料流未遭錯誤,條件產出true;若遭錯誤,則產出false。 #### istream產生false的情況 * 碰到檔案結尾(EOF, end-of-file)。 * 遇到無效輸入(型別不相容)。 :::info **從鍵盤輸入END OF FILE** * Windows 系統 : control-z + Enter * UNIX (包含MAC OS)系統 : control-d ::: :::info **錯誤Error** 編譯器雖無法偵測結構是否符合意圖,但可偵測出形式的錯誤。 常見的錯誤種類: * 語法錯誤(Syntax errors): 犯了C++程式的"文法錯誤(grammatical error)"。 以下為常見的語法錯誤 : ```cpp= // missing ) in parametar list for main int main ( { // Used colon ":", not a semicolon ";", after endl std::cout << "Read each file." << std::endl: // missing quotes "" around string literal std::cout << Update master. << std::endl; // second output operator is missing std::cout << "Update master." std::endl; // missing ; on return statement return 0 } ``` * 型別錯誤(Type errors): C++中的每個資料項目都有關聯的型別。 型別錯誤的例子之一為傳入一個字串字面值給預期一個int引數(argument) 的函式。 * 宣告錯誤(Declaration errors): 使用的名稱沒有宣告。 常見的兩種錯誤宣告錯誤: 1. 忘記為來自程式庫的名稱使用std:: 2. 拼錯識別字(identifier)的名稱 ```cpp= #include <iostream> int main() { int v1 = 0, v2 = 0; // 使用 "v" 而非 "v1" std::cin >> v >> v2; // cout沒有定義, 應為 std::cout cout << v1 + v2 << std::endl; return 0; } ``` ::: :::spoiler :::success - [x] 練習 1.14 : 寫出你自己的程式,從cin讀取一組整數並印出它們的總和。 ::: ### 4. if 述句 C++提供 **if 述句**支援條件式執行(conditional execution)。 用 if 來計數輸入的值連續出現多少次: ```cpp= #include <iostream> int main() { // currVal為我們要計數的值, 新的值讀入val int currVal, val = 0; // 讀取第一個數字,確保有資料處裡 if(std::cin >> currVal) { int cnt = 1; // 儲存次數 while(std::cin >> val) { // 讀取剩餘數字 if(val == currVal) // 若數字相同 ++cnt; // 次數加一 else { // 否則印出前一個數字出現的次數 std::cout << currVal << " occurs " << cnt << " times" << std::endl; currVal = val; // 記住新的值 cnt = 1; // 重置計數器 } } // 為最後一個輸入的值印出次數 std::cout << currVal << " occurs " << cnt << " times" << std::endl; } // 最外層的if述句結束於此 return 0; } ``` :::warning ![result](https://i.imgur.com/0PCSr36.png) **執行結果:** 輸入: 42 42 42 42 42 55 55 62 100 100 100 輸出: 42 occurs 5 times 55 occurs 2 times 62 occurs 1 times 100 occurs 3 times ::: 第一個if述句: ```cpp if(std::cin >> currVal) { // ... } // 最外層的if述句結束於此 ``` 確保輸入不是空的。if 會估算一個條件,為true,就執行接在後面的區塊。 一但有數字要計數,定義cnt計數每個數字出現的次數。 while主體是含有第二個if述句的區塊: ```cpp if(val == currVal) // 若數字相同 ++cnt; // 次數加一 else { // 否則印出前一個數字出現的次數 std::cout << currVal << " occurs " << cnt << " times" << std::endl; currVal = val; // 記住新的值 cnt = 1; // 重置計數器 } ``` if中的條件使用相等性運算子(equality operator, **==運算子**) 測試 val 是否等於 currVal。 若為true,則執行緊接條件後的述句。 為false(val 不等於 currVal),則會執行接在else後的述句。 :::danger C++ 的指定使用 = , 相等性(equality) 則使用 ==。 ::: :::info **C++的縮排及格式化** C++程式 大多 沒有格式的限制,代表放置大括號、縮排(indentation)、註解或 newline 的位置對程式的意義沒有影響。 格式化會影響程式的易讀性(readability)。C 或 C++的格式化並不存在單一風格,但縮排的慣例會在我們程式變越來越精密時變明顯。 挑選程式風格會時,思考會如何影響易讀性。選定一種風格後,前後一致使用它。 ::: :::spoiler :::success - [ ] 練習 1.15 : 若輸入的值皆相同,本節的程式會發生什麼? 若無重複的呢? - [ ] 練習 1.16 : 編譯並執行本節的程式,給他相同的值輸入。再給他不重複的值作為輸入執行。 - [ ] 練習 1.17 : 編輯 練習 1.10 ,讓他能處理第一個數字小於第二個的輸入。 ::: ## 五、 類別(class) 簡介 解決書店問題之前,需先理解剩餘的最後一個功能,藉由定義**類別(class)** 定義我們的 *資料結構*。 一個類別定義了一個型別,及與那個類別相關的一個運算。 類別機制是C++最重要的功能之一。 C\++專注的一個重點是,如何讓定義的**類別型別(class types)** 運作起來跟內建型別(built-in types) 一樣自然。 **要使用一個類別,需要知道三件事:** * 類別名稱。 * 類別定義於何處。 * 類別支援什麼運算 對我們的書店問題而言,我們假設 * 類別名稱為 Sales_item * 它定義於名為 Sales_item.h 的標頭檔內 **要使用程式庫的機能,必須引入(include)關聯的標頭**,亦透過標頭取用自己定義的類別。 通常標頭檔的名稱從該標頭的某個類別名稱衍伸。 我們寫的標頭檔通常會有後綴 .h , 某些為 .H 、 .hpp 或 .hxx。標準程式庫一般沒有後綴。 編譯器通常不在意標頭檔檔名形式,但有時IDE會。 ```cpp= #include <iostream> #include "Sales_item.h" int main() { Sales_item book; //讀取ISBN、售出本數及售價 std::cin >> book; //寫入ISBN、售出本數、總營收及平均價格 std::cout << book << std::endl; return 0; } ``` ### 1. Sales_item類別 要使用一個類別,不需要關心他如何實作,而是要知道該類別的物件能進行什麼運算。 每個類別都定義了一個型別(type)。型別名稱與類別名稱一樣,因此,Sales_item類別定義了一個名為Sales_item的類別。 與內建型別相同,我們可以定義某個類別型別的變數。如下: ```cpp Sales_item item; ``` 我們說的是item 是型別Sales_item 的一個物件。「型別Sales_item 的一個物件」也可稱為 「一個Sales_item 物件」 或 「一個Sales_item」。 除了定義變數,我們還能: * 呼叫名為 isbn 的函式從一個Sales_item物件擷取ISBN。 * 使用輸入(>>) 與輸出(<<) 運算子來讀取或寫入型別為Sales_item的物件。 * 使用指定運算子(=) 將一個Sales_item物件指定給另一個。 * 使用加法運算子(+) 來相加兩個Sales_item物件。這兩個物件的ISBN需相同。結果會是新的Sales_item物件,ISBN是相同的,而賣出本數和營收則是其運算元中對應的總和。 * 使用複合指定運算子(+=) 來將一個Sales_item物件加到另一個。 :::info **類別定義行為** 類別作者定義了此類別之物件能進行的 *所有* 動作。 也就是說,Sales_item類別定義了物件創建時與指定、加法與輸入運算子套用到Sales_item時,會發生什麼。 類別作者決定了所有在類別型別物件上的所有運算。就現在而言,我們知道能在Sale_item物件上進行的運算只有以上這些。 ::: #### 讀取或寫入 Sales_item :::warning ![result](https://i.imgur.com/m5egZjx.png) **執行結果:** 輸入: 0-201-70353-X 4 24.99 輸出: 0-201-70353-X 4 99.96 24.99 ::: 程式的開頭使用了一個新的 #include 的形式。 * 來自標準程式庫的標頭被包在角括號(angle braacket ,< > )中。 * 並非來自標準程式庫的標頭被包在雙引號(double quotes, " " )。 main 內定義了一個名為 book 的 Sales_item 物件,用來存放標準數入讀到的資料。 下一個述句讀取資料到那個物件。 第三個述句將之印到標準輸出,在印出endl。 #### 相加 Sales_item ```cpp= #include <iostream> #include "Sales_item.h" int main() { Sales_item item1 ,item2; //讀取一對交易紀錄 std::cin >> item1 >> item2; //印出總和 std::cout << item1 + item2 << std::endl; return 0; } ``` :::warning ![result](https://i.imgur.com/qrSixwU.png) **執行結果:** 輸入: 0-201-78345-X 3 20.00 0-201-78345-X 2 25.00 輸出: 0-201-78345-X 5 110 22 ::: 在這裡讀取兩個輸入並寫出他們的總和與之前的這個程式看起來很相似。 ![reference](https://i.imgur.com/fk5VyEm.png) 但概念不一樣。 在 int 的例子裡產生的是傳統的和,即兩個數值加總。 但在 Sales_item 物件的例子中,概念上賦予加總一個新的意義,即兩個 Sales_item 物件的組成元素各自相加。 :::spoiler :::success - [ ] 練習 1.18 : 使用 Sales_item.h 撰寫一個程式,讀取一組書籍販售記錄,再將每筆交易記錄寫到標準輸出。 - [ ] 練習 1.19 : 寫一個程式,讀取兩個具有相同ISBN的Sales_item物件,並產生總和。 - [ ] 練習 1.20 : 寫一個程式讀取具有相同ISBN的數筆交易記錄。寫出所讀取的所有交易記錄之總和。 ::: ### 2. 成員函式初探 檢查兩物件是否擁有相同 ISBN 。如下: ```cpp= #include <iostream> #include "Sales_item.h" int main() { Sales_item item1, item2; std::cin >> item1 >> item2; //確認 item1 和 item2代表同一本 if(item1.isbn() == item2.isbn() ){ std::cout << item1 + item2 << std::endl; return 0; // 代表成功了 }else{ std::cerr << "Data must refer to same ISBN" << std::endl; return -1; // 代表失敗了 } } ``` :::warning ![result](https://i.imgur.com/xpKgLp9.png) **執行結果(1):** 輸入: 0-201-78345-X 3 20.00 0-201-78345-X 2 25.00 輸出: 0-201-78345-X 5 110 22 ![result](https://i.imgur.com/nu1BFXe.png) **執行結果(2):** 輸入: 0-201-78345-X 3 20.00 0-201-99638-X 2 25.00 輸出: Data must refer to same ISBN ::: 條件測試失敗,執行else後的區塊,印出一個訊息,並回傳一個代表錯誤的值。 #### **成員函式(member function)** * 定義為某個類別一部分的函式。 * 又稱**方法(methods)**。 以物件身分呼叫一個成員函式: ```cpp item1.isbn ``` * 使用點號運算子(dot operator, **. 運算子**)表示「名為item物件的isbn成員。 * 點號運算子只適用於類別型別的物件。 * 左邊為一類別型別的物件。 * 右邊指名那個型別的成員名稱。 使用呼叫運算子(call operator, **()運算子**) 呼叫一個函式。 ```cpp item1.isbn() ``` * 呼叫運算子包圍了一個引數列(a list of **arguments**,可能為空 ) ,這裡的 isbn不接受引數。 * 上例呼叫isbn函數。此函數回傳貯存在item1中的ISBN :::spoiler :::success - [ ] 練習 1.21 : 寫一個程式,讀取數筆資料,計數每一個ISBN出現幾次。 - [ ] 練習 1.22 : 給予前一個程式代表多個ISBN的多筆交易記錄測試他。每個ISBN的交易應被視為同一組。 ::: ```cpp= #include <iostream> #include "Sales_item.h" int main() { Sales_item total; // 存放下一筆交易紀錄資料的變數 // 讀取第一筆交易,確保有資料可以處理 if(std::cin >> total) { Sales_item trans; // 存放運行總和的變數 //讀取並處理下一筆交易記錄 while(std::cin >> trans) { if(total.isbn() == trans.isbn() ) total += trans; // 更新累積的TOTAL else { std::cout << total << std::endl; total = trans; // 指向下一本 } } std::cout << total << std::endl; }else { //沒有輸入!警告使用者 std::cerr << "No Data?" << std::endl; return -1; } return 0; } ``` :::warning ![result](https://i.imgur.com/cbsJ1vF.png) **執行結果** 輸入: 0-201-78345-X 3 20.00 0-201-78345-X 2 25.00 0-201-78345-X 3 20.00 0-201-78345-X 2 25.00 ^Z 輸出: 0-201-78345-X 10 220 22 ::: <!-- ``` c 小文是一個小學生,他要計算一堆個位數字的乘積,有好幾題,幫他寫一個程式做作業ㄅ ---------------------------------------------------------- 輸入說明: 第一行輸入題數 n 第二行 輸入一個數字m,之後後輸入m行由空格分開的數字,共n行。 輸出說明: 輸出n行 分別為每一題的乘積 ---------------------------------------------------------- 輸入範例: 4 5 6 2 3 2 1 3 2 4 1 4 0 1 6 2 5 4 4 5 1 2 輸出範例: 72 8 0 160 ``` ```cpp= #include <iostream> using namespace std; int main() { int n,m; cin >> n; // 指定題數 for(int i = 0 ; i < n ; i++){ // 執行n行 int ans = 1, c = 0; cin >> m; // 指定有多少整數 for(int j = 0 ; j < m ; j++){ // 讀取m個數字 cin >> c; ans *= c; } cout << ans << endl; } return 0; } ``` ![](https://i.imgur.com/bsmcLdm.png)-->