物件導向的程式語言(Object Oriented Program 簡稱 OOP), 端看字面意義就覺得博大精深讓人忘而怯步, 如果改翻譯成"活化的程式語言", 或者更貼近一點用"生活化的程式語言"也許能令人眼睛為之一亮, 有興趣學習. C++ 蘊藏著 OOP 的特性, 經過編譯後本質上仍是 C 語言, 它執行速度之快是最讓人激賞的地方. 以下列出 C++ 常用的關鍵字:
1. 數學四則運算元符號: +, -, *, ÷, % 2. 邏輯運算元符號: !, &&, ||
3. 比較運算元符號: ==, !=, >=, <=, >, <
4. 位元運算符號: ~, &, |, ^, > >, < <
5. 指定(assign)運算符號: =, ++, --, +=, -=, *=, /=, %=, &=, |=, ^=, >>=, <<=
6. 繼承單冒號 :
7. 類型或整體區域引用雙冒號 ::
8. 優先或函式引用小括號 ( )
9. 陣列或向量引用中括號 [ ]
10. 區塊敘述大括號 { }
11. 物件引用句號 .
12. 指標引用箭號 ->
13. 區塊陳述與指令: if( ) { } else { }, switch( ) { case: }, while( ) { }, do{ } while( ), for( ){ }
14. 流程或迴圈控制: break, continue
15. 條件判斷式 ( ) ? true-expression : false-expression
16. 所有變數名稱都必須宣告資料型態(type), 包含函數(函式名稱也是變數之一), 如果變數使用 = 初始化時, 通常資料型態可以根據上下文推斷出來, 因此可以宣告成 auto 資料型態讓編譯器代理. C++ 內建數值型資料型態有 unsigned, char, string, int, long, long long, float, double, long doublet, bool
17. 新資料類型使用"class 新名稱"來宣告, 它是類型化身(instantiate)的來源, 類型新名稱之後可以用冒號 : 繼承父類型, 如要開放給繼承者使用父類型的方法, 需使用公開繼承關鍵字 : public 這樣化身之後才能使用所繼承的方法. 在類型區塊內所定義的變數名稱(variable)即為化身後的物件成員, 而定義的從屬函式(member function)特稱方法(method), 與類型同名稱的函式稱為建構法, 若同類型名稱前面再加上漂浮線 ~ 的函式則稱為解除法, 執行建構法將會產生物件的分身. 新類型經由建構法將成員組成新物件, 化身成分身 (instance), 因此一旦宣告新類型名稱, 它就成為新的資料型態(type).
18. class 新類型名稱 { } 區塊內敘述摘要:成員宣告 變數型態 變數名稱 ;
函數型態 方法名稱 (輸入資料型態列表, ... ) { }
友類認同列表 frind class
私密區域 private:
保護區域 protected:
公開區域 public:
建構法 新類型名稱( ) { }
解除法 ~新類型名稱( ) { }
19. 在類型(class)的區塊 { } 裏面, 若無特別指定, 內定(default)就是私密區域(private:), 它會被隱藏起來, 只有該類型本身可以直接存取, 但友類(friend class)或友方(friend function)經由 friend 的宣告獲取私密區域成員的存取權. 而繼承類型會繼承保護區域的成員, 但不包含私密區域的成員, 並且要用關鍵字公開繼承(:pupblic)後, 類型繼承者的分身才見的到所繼承的方法. 公開區域則是開放分身在類型的區域外部存取成員, 因此透過公開方法間接在類型內部進行私密區域成員的存取是合乎規定的.
20. 新類型建構法所回傳的是物件分身(instance), 若使用前置關鍵字 new 的話則只回傳物件分身的指標(pointer of instance), 這樣可減少大量的物件複製的動作. 物件使用句點 . 引用成員, 但指標必須要用箭頭符號 -> 來指定成員, new 的作用在於動態配置一塊記憶體作為分身的棲息地, 因此之後要使用 delete 將它移除才可回收再利用. 否則會造成記憶體缺憾(memory leak).
21. 在類型的方法裏面, 可以用關鍵字 this, 它是一個指標(pointer), 若區域內的變數名稱與類型的成員名稱相同時, 該變數在此區域內只能用 this 指標加上鍵號 -> 來加以區別. 當方法用 return this; 時就等同傳回本身的指標, 分身透過本身的方法回傳本身指標時, 後續可以用號鍵 -> 來鏈接其它方法接序執行. 如果分身的方法執行到最後用類型建構法回傳物件, 等同另起爐灶複製(clone)出該類型的分身. 雖然會有大量的複製動作, 但後續也可以用句號 . 方便鏈接其它方法接序執行.
22. 函式摘要函式透過函式宣告: 輸出型態 名稱(輸入型態列表, ... ) { } ,之後引用 名稱(參數) 觸發執行
函式執行到最後的傳回值(return)稱為函數
如果要重新指定運算元符號的函式, 可以使用前置 operator 宣告新的運算(函)式
函式針對不同的資料輸入型態,使用相同的名稱重複宣告,這個動作稱為加載(overload),
新類型的建構函式(方法)也可根據輸入的參數不同,用相同名稱 overload 方式分別處理
23. 所有敘述或宣告結束後要使用分號 ; 作結尾 , 包含新類型 class 宣告的大括號結尾 { };
24. 單行註解 //
25. 多行註解 /* */
26. 如何了解 C++ 四種變數宣告的不同用義: 變數, *指標, &別名, &&右值參照, 指標/別名/右值等變數用於大量記憶體傳遞時無需複製內容, 只用指標互相傳遞. &別名/&&右值參照都會指向特定目標,右值指向暫存區的內容, 當輸入或輸出參數佔用記憶體資料量龐大時, 用指標( *, &, &&)來傳遞資料因無需複製內容,因此變得簡潔又有效率.
變數: variable name指標: variable pointer *
別名: alias name &
右值參照: rvalue reference &&
後記:
1. virtual function 空殼函式, 宣告在類型內的函式, 可以讓繼承者自行改寫(override)的函式.
2. 抽象(abstract)類型是內含一個空殼函式指定為 0 的類型, 用於繼承但不得做為物件化身
// abstract class
class Abstract { virtual void _( ) =0; }
3. 定義新類型除了用 class 外, 也可以用 struct, 差別在於 class 內定是私密區域(private:), 但 struct 內定是公開區域(public:)
4. c++ 依照將中小大括號 [ ] ( ) { } 順序組合起來就是 lambda function(希臘字母 λ 函式), 中括號 [ ] 用於捕捉函式區塊內的變數, 將它們塞進 λ 函式加以運用. λ 函式 ( ) { } 就像一般的函式宣告, 把輸入參數放在小括號裏面. 大括號 { } 內容就是 λ 函式所封裝的程式碼簡稱 closure. 如果在 c++ 程式開頭處將 var 定義(#define)成 auto, 再將 function 定義(#define)成 [ ], 就可以讓它長的像是 Javascript, 這種定義(即使合法也)應儘量避免放在函式的輸入變數或輸出函數上, 以免造成誤解, 用 c++ 寫一個 λ 函式接收函數右值的程式範例:
#define var auto // typedef auto alternative #define function [ ] // capture nothing to act as a normal JS function
#include <stdio.h>
float f(float &&temp ) { // oC(celsius) to oF(fahrenheit)
var lambda = function (var x) { return x*9.0/5+32; } ; // define λ(x) = 9x/5 +32
return lambda(temp); // call λ(x) to transform x value, then return
}
float c( ) { return 30; } // return temperature in oC
int main( ) {
printf("f( a( ) ) = %f\n", f( c( ) ) );
}
沒有留言:
張貼留言