# include系列 - #include \<iostream> - #include \<cmath> - #incluse \<iomanip> - #include \<cstdlib> - #include \<ctime> - #include \<string> - #include \<vector> - [#inlcude \<list>](https://hackmd.io/h_enG5FyRWCVzY-O4A3wUg?view#list) - [#include \<map>](https://hackmd.io/h_enG5FyRWCVzY-O4A3wUg?view#map-and-multimap) - [#include \<stack>](https://hackmd.io/h_enG5FyRWCVzY-O4A3wUg?view#stack) ___ # 單一鍵 - \n - \t - \r - ctrl+z \(EOF,顯示為^Z) - 交集聯集 ___ # include 函式說明以及常用member function ## \<iostream> ```cpp= cin>>變數; cout<<訊息; cerr<<""; // 除了印到螢幕外也記錄到log檔協助debug ``` > 讀入與寫出 ## \<cstdlib> ``` cpp= string.length(); string.size(); ``` > 回傳字串長度 ```cpp= system("pause"); ``` > 強制程式在執行到那一行的時候停止,終端機印出以下字串 Press any key to continue . . . 在按下任意鍵以後,程式繼續執行。 ## \<iomanip> ### 四捨五入 ```cpp= cout<<fixed<<setprecision(正整數)<<""; ``` > 設定小數位數,以四捨五入計算,寫cout<<setprecision<<fixed<<"";倒過也沒差 ### 排版設定 ``` cpp= cout<<setfill(字元)<<setw(正整數)<<""; // 設定字串以幾格填入 ``` #### 舉例: ``` cpp= cout<<setw(10)<<endl; // fuck cout<<setfill('0')<<setw(10)<<"fuck"<<endl; //000000fuck ``` ## \<cmath> ``` cpp= log(小數) // 這條函式不用include <cmath>就可以使用,但是你一定會忘記 // 就是ln pow(a,b); ceil(小數); floor(小數); abs(小數); fmod(小數,小數); // 小數專用的%,舉例fmod(2.6,1.2)=0.2 exp(小數); // 產生尤拉數的n次方 square(小數); sqrt(小數); sin(小數); cos(小數); tan(小數); ``` ___ # 變數 ## 種類 - int 整數 - double 浮點數 - char 單一字元 - string 字串 - bool 布林值 - unsigned int/double 正整數/小數 - size_t 回傳她在memory所佔的bit數,從unsigned在STL定義的 - 在變數種類前加入long使可以儲存的字元數增加 ![](https://i.imgur.com/1EyswU6.png) ___ ## 變數宣告 **宣告方式:** - 暫時宣告:變數種類+變數名稱; ``` CPP= long int a; long int a=0; ``` 在宣告時可以進行定義,也可以不用。 - 不變宣告:輸入的變數不能再修改 const 變數種類+變數名稱; ```C++= #include <iostream> using namespace std; int main {const int a;} ``` ___ ## 資料型態轉換 - 強制轉換 ```CPP= #include <iostream> using namespace std; int main() { int a = 2; double b=double(a); } ``` - cast operator(轉型運算子) ```CPP= #include <iostream> using namespace std; int main() { int a = 2; double b=static_cast<double>(a); } ``` - string lib ```CPP= #include <iostream> #include <string> using namespace std; int main() { int a = 2; string b = to_string(a); } ``` - stoi、atoi...等cstring的用法請看[cstring](#cstring) ## 變數區域性 **Storage Classes與Scope rule** 1. global variable:程式界的公車。不推,因為記憶體問題與可讀性和容易髒掉。 2. static variable:建立一個全域可讀變數,但是只會初始化一次,接下來只能由function做operation,不能重新定義。 ```CPP= #include <iostream> using namespace std; int main() { static int x=50; } ``` 3. local variable: For only local scope, 僅存在那一個scope 4. function prototype variable: For function prototype scope,其實就是function parameter。 - 每一次拿變數都是先local->(static)->global,也就是從inner的loop拿變數。 - 如果想在一個block裡使用同一名稱但是屬性為global的變數,可以打::variable_name ___ # if使用 if(條件) { 做事 } ```CPP= #include <iostream> using namespace std; int main() { int a=3,b=2; if(a>b) { cout<<""<<endl; } else if (a==b) { cout<<""<<endl; } else { cout<<""<<endl; } } ``` ___ # while and do while - while ``` cpp= while (條件) { 做事; } ``` - do while > 會先執行指令,如果條件成立才會繼續執行 ``` cpp= do { 做事; }while(條件); ``` ___ # for - 往上數 ``` cpp= for (int i = 0; i<次數; i++) { 做事; } ``` - 往下數 ``` cpp= for int i = 次數; i > 0; i-- ) { 做事; } ``` ___ # switch ```cpp= switch (變數) { case 變數可能: 做事; break; case 變數可能2: 做事: break; default: 當上面全部都沒發生時要做的事情; } ``` ___ # 隨機 ## 正常隨機寫法 ```CPP= # include <iostream> # include <ctime> # include <cstdlib> int main() { int i; //固定時間種子碼 srand(time(0)); //產生隨機數字(0~RAND_MAX) i=rand(); cout << "The random num is: " << i << endl; } ``` - `rand()`會產生0~2147483647之間的整數 - 在範例程式中,`time`的參數給`0`或者是`NULL`會有相同效果 - 如果要產生多個亂數,不需要把`srand(time(0))`放到迴圈裡面,只需把`i=rand();`放進去即可 ## 特定隨機亂數寫法 - 假設現在要產生一個10~100的隨機亂數 ```CPP= # include <iostream> # include <ctime> # include <cstdlib> int main() { srand(time(0)); // 印出10~100之間的隨機亂數 cout << "The random num is: " << rand() % 91 + 10 << endl; } ``` ___ # 結束程式的方法 ``` cpp= return 0; ``` ```cpp= exit( 0 ) // 作業系統會根據exit 後面的數字去應對不同的中止程式方法 // 0:normal 1~other:error ``` # function def 首先,在main之前寫出function prototype ```CPP= #include <iostream> using namespace std; int square(double); //function prototype, or function declaration void print(string); //function prototype, or function declaration // 是說不寫function prototype他也會給過就是了。 /*在這裡也可以直接規定變數,例如"void print(string="fuck")", 稱為預設值(Default value),在沒有輸入變數或輸入變數不夠的時候, 從左而右開始取代。*/ int main() { int x = 4; string z = "yeah"; cout << "the original value is "<< x << endl; // 4 cout << "the operation of x is " << square(x) << endl; // 16 print(z); // yeah } int square(double x) { return x*x; //不寫return就是編譯錯誤 } void print(string z) { cout << z << endl; // 可以寫單純return; return; } ``` - function parameter--就是`void print(string z)`的`z`--與local variable一樣時:爆炸 - 不能巢狀定義 - void function(void)也是可行的,並且也會提高程式可讀性。 - inline function():"建議"編譯器使用[複製]的方式將function回傳到程式中。編譯器會自行判斷要不要接受建議。 - function overloading:函數名稱可以一樣,但是,函數至少要有其中一個種類parameter不一樣,例如:變數數量、變數種類......等。 - 如果parameter要傳入array,要寫"array[]"而非單純的"array"。 - 如果要傳入vector,則要寫"vector\<int>" ___ # function templates - 針對每一個輸入的變數客製化變數型態,下面class 可以替換成typename。 - 注意: fucntion Template要寫在使用之前,不然會爆炸 ```cpp= #include <iostream> using namespace std; // 規定Template種類 template < class T > // 使用Template建立function T function(T value1, T value2) { T result; result = (value1 > value2) ? value1 : value2; return result; } int main() { int result; // 在使用result的時候就會自動套用Template result = function(12, 10); cout << result << endl; } ``` - 像是以上程式碼中,T就可以是任何型態\(int、float...) ___ # 自定義資料型態enumeration - enum TypeName - 建議在定義的時候變數用大寫,與變數區分 - 可以賦予初始值,之後的值都會是前一個值+1,否則都是從0開始 ```CPP= #include <iostream> using namespace std; enum fruit { apple, banana, lemon, mango, orange }; int main() { enum fruit { apple = 1, banana, lemon, mango, orange }; } ``` - 更多enumerate的用法可以看[參考資料](#參考資料)的第七點 ___ # Referance 與 Referance Parameter - Referance ```CPP= int a = 1; int &b = a; // 一定這時候就要init了,且下面無法再定義一次b ``` 則如同綁定a,b;對其中一者做改變,另一者也會受到一樣的改變 - Referance Parameter ```CPP= #include <iostream> using namespace std; void squareref(int&); int main() { int x=2; cout << "x is :" << x << endl; // 2 squareref(x); cout << "x is : " << x << endl; // 4 } void squareref(int& x) { x *= x; } ``` 在上面程式中,可以看到x值改變了以後直接背回傳原先的x,所以印出4。 ___ # array - 資料型態必須一樣 - 如果index的值大於現有的數量,其他位數會補0。 - 如果index的值小於現有的數量,會回傳一個不知所云的值。 - array[]中的[]不要傳入變數,會炸掉。 ## 一維array ```CPP= #include <iostream> using namespace std; int main() { int array1[4]={a,b,c,d}; int array2[4]={}; int array3[][]={};//巢狀array } ``` ## 二維array ![](https://hackmd.io/_uploads/r1WyWnuc2.png) ## pointer 與一維array ```cpp= #include <iostream> using namespace std; void function(int*); int main() { int arr[10] = {0,2,0,0,0,0,0,0,0,0}; function(arr); } void function(int* arr) { arr[1] *= arr[1]; } ``` pointer 取一維array值有4種方法: 1. array[0] 2. \*(array + 2) 3. array_Ptr[2] 4. \*(array_Ptr + 2) ## pointer 與2維array ### pointer指到完整array ```cpp= #include <iostream> using namespace std; int main() { // 宣告一個pointer 指到一個完整的array,而不是指到array的第一格 int(*arrayPtr)[5]; int array[5][5]; // 初始化一個array for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) array[i][j] = i; // 定義arrayPtr的位置 arrayPtr = array; // 取二維array中第2個array裡面的第3個值 cout << *(*(arrayPtr+1)+2) << endl; return 0; } ``` ### pointer指到array第一格 ```cpp= int** calculate(void) { int matrix1_h,matrix1_w,matrix2_w, matrix2_h; cout << "Enter rows and columns for first matrix:" << endl; cin >> matrix1_h >> matrix1_w; cout << "Enter rows and columns for second matrix:" << endl; cin >> matrix2_h >> matrix2_w; if (matrix1_w != matrix2_h) { cout << "Cannot multiply these two matrixes." << endl; return NULL; } int ans[matrix1_h][matrix2_w]; int* ansPtr[matrix1_h]; for (int i = 0; i<matrix1_h; i++){ ansPtr[i]=ans[i]; for (int j = 0;j<matrix2_w;j++){ ans[i][j] = i*10+j; } } return ansPtr; } ``` ## array與string ```cpp= #include <iostream> using namespace std; int main() { const char* array[4] = { "Heart","Spade","Dimond","Clubs" }; cout << array[0] << endl; // Heart cout << array[1] << endl; // Spade cout << array[2] << endl; // Dimond cout << array[3] << endl; // Clubs return 0; } ``` 注意: 如果要照上面打,則const不可省,因為array內的值是固定的。 一般比較常在string這樣用 ___ # vector(更像list的東西) - 要include \<vector> - 可以直接判斷是否== ## 創建vector ```cpp= vector <int> vector1 (7,0); ``` - 上述的含意 : 創建一個吃int,名字為vector1,內值數量7個的vector且初始值 = 0 - vector 在創建的時候若沒有初始化,則初始值為0 ## vector member funtion ### 回傳vector1的長度 ```cpp= vector1.size(); ``` ### 把vector1複製貼上到vector2 ```cpp= vector<int>vector2(vector1); vector3=voctor1; ``` - 1、2都可以完成 ### 提供bundary checking的方法 ```cpp= vector1.at(1)=15; ``` - 注意,是()不是\[] ### 在原本vector的後面新增元素 - 注意,這個動作會增加原先列表的長度 ```cpp= vector.push_back("element"); ``` ### 將vector歸零 ```cpp= vector.clear(); ``` ___ # string - 創建一個長度是字串+1的char array - 結尾會以\0,NULL,ASCII編碼=0的東西結尾 ## 定義string ```cpp= string str1 = "test str1"; string str2("test str2"); ``` ## string function ### 回傳字串長度(從1算起) ```cpp= str.length(); ``` ### 其他常用函式 ```cpp= string1[1]; string1 += string2; string[1]='0'; string.at[1]='5' ``` ### 查詢字串是否為空 ```cpp= string1.epmty(); ``` ### 類似python slicing的功能 ```cpp= str1 = "TryHard" str1.substr(0,2); // Tr str1.substr(2); // yHard ``` - 跟python slicing的邏輯完全不一樣,`0,2`會顯示從第0位開始數之後的2個位數 ___ # argc/ argv :::info 可以透過main function的argv變數餵食參數,可以[參考這篇文章](https://blog.gtwang.org/programming/c-cpp-tutorial-argc-argv-read-command-line-arguments/) ::: - 固定寫法 ```cpp= #include <iostream> using namespace std; int main(int argc, char** argv) { /*你的程式碼*/ } ``` - argv列表會以字串回傳所有的參數 - 如果想要在VS裡面傳遞參數,可以點開`專案`->`屬性`->`偵錯`->在`命令引數`左側打上你想要打的側資。 - 特殊輸入用法([參考資料](https://learn.microsoft.com/zh-tw/cpp/cpp/main-function-command-line-args?view=msvc-170)) | 命令列輸入 | argv[1] | argv[2] | argv[3] | | -------- | -------- | -------- | -------- | | `"abc" d e` | abc | d |e | | `a\\b d"e f"g h` | a\\\b | de fg |h | | `a\\\"b c d` | a\\"b | c |d | | `a\\\\"b c" d e` | a\\\b c | d |e | | `a"b"" c d` | ab" c d | | | ___ # getline ```cpp= getline(cin,str1) ``` ## 功能 同cin,但是他可以吃空白鍵,而且他只能吃string。 ## 發生錯誤 - 在如果前面曾經輸入任何東西的時候,總是會按下"enter",則buffer會吃進你輸入的東西+一個換行符號"\n"作為結尾。 - 而cin 或 getline 會吃進去在\n以前符合變數型態的任何東西進去記憶體。 - 然而,這時候buffer還有一個該死的\n阿!所以她讀到\n時就會停止,但是\n的東西已經被拿完了,所以就會出現getline出不來的現象 ## 解決方法 - cin.ignore() 清除buffer一個字元 - cin.ignore(1000000,'\n') 如果手賤不小心多打了一些垃圾進去,那就通通清掉,看1000000個字原先被清完還是先清到\n。 ___ ## cin.getline ```cpp= cin.getline(<要放的位置>,<要放的大小>,<要終止的符號>) ``` 注意 因為最後一格要存\0,所以最後只能存<要放的大小 - 1>個char ___ # iterator - 概念類似於STL內的指標 ## 一般用法 - 可以使用begin()、end()把list的位置回傳 - 注意:end()會回傳list最後一個元素的**下一個元素的位置** ```cpp= #include <iostream> #include <vector> using namespace std; int main() { vector<int>vec1 = { 0, 1, 2, 3 }; vector<int>::iterator it; for (it = vec1.begin(); it != vec1.end(); it++) { cout << *it << " "; // 0 1 2 3 } return 0; } ``` ## iostream_iterator - 一種處理input/output iterator的header file ```cpp= #include <iostream> #include <iterator> using namespace std; int main() { cout << "Input 2 numbers: "; // 創建istream_iterator obj istream_iterator<int> inputInt_Ptr(cin); // inputInt_Ptr是一個Ptr(廢話) int num1 = *inputInt_Ptr; inputInt_Ptr++; // 把inputInt_Ptr移到下一個位置 int num2 = *inputInt_Ptr; ostream_iterator<int> outputInt_Ptr(cout); cout << "The sum: "; // 變更reference的時候就會回傳值 *outputInt_Ptr = num1 + num2; cout << endl; return 0; } ``` # Pointer :::info 透過這種方式,可以避免因為未知的記憶體大小而導致overflow等優點 ::: ## difference between & and * operation | | &| \* | | -------- | -------- | -------- | |在等號前|referance,詳情見[referance章](#Referance-與-Referance-Parameter)|定義一個資料為pointer| |在等號後|回傳某一個變數在記憶體的特定位置|回傳\*Ptr所指到的記憶體相對位置所代表的值| ## NULL pointer 如果一個pointer的值直接被assign成0 or NULL 我們稱之為NULL pointer,表示pointer不指到任何地方。 ## pointer 一般使用範例 ```cpp= #include <iostream> using namespace std; int main() { int x; int* yPtr; x = 7; yPtr = &x; cout << "The address of x is: " << &x \ << "\nThe value of yPtr is: " << yPtr << endl; cout << "\nThe value of x is: " << x\ << "\nThe value of *yPtr is: " << *yPtr << endl; return 0; } ``` 結果如下 ![](https://i.imgur.com/fFcRcoz.png) ## const操作pointer 1. 最基礎。 ```cpp= int* xPtr = &x; ``` 2. 指到的值不能變,不過依然可以用原變數(y)去修改。 ```cpp= const int *yPtr = &y; ``` 3. 指向的箭頭不能再更改,pointer的指向位置固定。 ```cpp= int* const xPtr = &z; ``` 4. 就...指向的值與指向位置都不能改摟。 ```cpp= const int* const mPtr = &m; ``` ### 單純以pointer餵值給function ```cpp= #include <iostream> using namespace std; void function(int*); int main() { int a = 1; int* aPtr = &a; function(a); cout<<*a<<endl; } void function(int* x) { *x = *x * *x * *x; } ``` ## pointer與function - function protal type: void <這個函式的名稱>(<指到的函式要回傳的資料型態>(*)(<指到的函式要吃的資料型態>)); - 使用function: <這個函式的名稱>(<要指到的函式>); - function def: void <這個函式的名稱>(<指到的函式要回傳的資料型態>(*<指到的function在你這裡叫甚麼>)(<指到的函式要吃的值>)); ```cpp= #include <iostream> using namespace std; int cube(int); void print(int, int (*)(int)); int main() { int x; cout << "給一個值,會印出該值的3次方:"; cin >> x; int* x_Ptr = &x; print(x, cube); return 0; } int cube(int x) { return x * x * x; } void print (int x, int (*cube)(int)) { cout << (*cube)(x) << endl; } ``` ___ # sizeof ```cpp= #include <iostream> using namespace std; int main() { int x; int xarray[5] = {}; cout << sizeof(x) << endl;//4 cout << sizeof(xarray) << endl;//20 } ``` ___ # file ## include \<fstream> ## 寫入檔案 ```cpp= #include <iostream> #include <fstream> #include <string> using namespace std; int main() { string input; // 開啟檔案或開新檔進行編輯 ofstream outclient("file.txt", ios::out); //若檔案無法開啟的解決方法 if (!outclient) { // 跳錯誤訊息並記錄到log檔 cerr << "黨無法被打開,你愚蠢的行為害死了毛主席 social creddit -1000000" << endl; // 強制結束 exit(1); } // 決定你要寫入甚麼 cout << "好啦,要寫什麼幹話都丟啦" << endl; cin >> input; // 寫入檔案 outclient << input << "\n因為我不知道要加甚麼" << "\n只是想讓你知道這樣也可以" << endl; // 關閉檔案 outclient.close(); } ``` - 第1行 推薦寫法: ``` cpp= ofstream outclient; outclient.open("client.exe", ios:app) ``` - 第11行 如果最後寫的是ios::app 或 ios::ate 在原本後面的內容加新的文字,原來在file的內容不會消失 - 第11行 如果最後寫的是ios:binary 以二進位的方式處理輸入與輸出 - 第13行 錯誤出現的處理一定要寫 有可能的錯誤: 沒有權限訪問 之類的 ## 讀出檔案 ```cpp= #include <iostream> #include <fstream> #include <string> using namespace std; int main() { string input; // 開啟檔案或開新檔進行編輯 ifstream inclient("file.txt"); //若檔案無法開啟的解決方法 if (!inclient) { // 跳錯誤訊息並記錄到log檔 cerr << "黨無法被打開,你愚蠢的行為害死了毛主席 social creddit -1000000" << endl; // 強制結束 exit(1); } // 讀出所有東西並列印到螢幕 while (inclient >> input) { cout << input << endl; } // 把指標放回文件的開頭 inclient.clear(); inclient.seekg(0); // 透過getline實現一次讀一行的行為 while(getline(inclient, input)){ cout << input << endl; } } ``` - 如果需要重複讀檔,要加上下面兩句 ```cpp=30 inclient.clear(); // reset eof state inclient.seekg(0); // make the index to the beginning ``` ## seekg(ifstream)/ seekp(ofstream) - pointer index會指在正在讀檔的下一個位置 - 使用前面一定要加上inclient.clear() ```cpp= inclient.clear(); inclient.seekg(int, ios::beg); ``` - 要把指標放到第幾格 - ios::beg (default) 從第0格檔案位置開始移到第n個 - ios::cur 從指定位置開始移到第n個 - ios::end 從最後一個的位置開始往回移n個 ## tellg(ifstream) / tellp(ofstream) 回傳現在指標位置 ___ # struct ## 定義: ```cpp= #include <iostream> using namespace std; int main() { struct StudentInfo { string FirstName; string LastName; int StudentID; int grade; int* nextPtr; }; ``` ## 輸入資料 ```cpp=+ StudentInfo student1{ "近平", "習", 198964, 0 }; ``` ## 修改資料 ```cpp=+ student1.grade = 5; ``` ## 使用 ```cpp=+ cout << student1.grade << endl; cout << student1 -> nextPtr << endl; } ``` ___ # cstring ## strcpy(S1, S2) - 將S2複製到S1 ## strncpr(S1, S2, int x) - 將S2複製x格到S1 - 記得cpr之後要自己補\0 ```cpp= S1[x] = '\0'; ``` ## strcat(S1, S2) - 將S2的值接上S1 ## strncat(S1, S2, int x) - 將S2的x個值接上S1 ## strcmp(S1, S2) - 回傳是否相等; - 相等回傳0 - 反之則比較ACSii code 大於回傳1 小於回傳-1 ## strncmp(S1, S2, int x) - 回傳從0到x格是否相等 - 其餘同strcmp ## strtok(S1, char c) - S1.split(c\) - 回傳指標,也是char array的第n格 - 若沒有得切則回傳null - 根據網路上的說法,在多線程的時候會導致功能錯誤 ``` c++= #include <iostream> #include <string> #include <cstring> using namespace std; int main() { char S1[] = "Pls don't flunk me."; char* tocken_S1_Ptr; tocken_S1_Ptr = strtok(S1, " "); cout<<tocken_S1_Ptr<<endl; // pls tocken_S1_Ptr = strtok(NULL, " "); cout<<tocken_S1_Ptr<<endl; // don't while (tocken_S1_Ptr != NULL) { tocken_S1_Ptr = strtok(NULL, " "); cout<<tocken_S1_Ptr<<endl; // flunk // me } } ``` ## strtok_s(string s, char delimiter, char &sPtr) - strtok的替代品,在VS裡面不能使用strtok ```cpp= #include <iostream> #include <cstring> using namespace std; int main() { string hello = "Hello world. I'm a new to here."; char* strPtr = &hello[0]; char* nextStr_tok = NULL; char* str_tok = strtok_s(strPtr, " ", &nextStr_tok); while (str_tok != NULL) { cout << str_tok << endl; str_tok = strtok_s(NULL, " ", &nextStr_tok); } return 0; } ``` ## strlen(S1) - 回傳長度,不含\0 ## atof - string to double ## atoi - string to int - 如果傳喚出來的數字超過int上界不會報錯,會輸出最多到哪裡 ## stoi - string to int - 如果轉換出來的數字超過int上界便會報錯 - 這是\<string\>不是cstring ## atol - string to long int - 超沒用,因為在windows, long int = int ## strtod - 回傳小數位數後的精確值 - 現在用不到,等你哪天瘋了才可能用到 ## strtol - 回傳整數位數後的精確值 - 現在用不到,等你哪天瘋了才可能用到 ## strtoul - 回傳正整數後的精確值 - 現在用不到,等你哪天瘋了才可能用到 ## strchr(S1, char c) - 從0開始尋找c在S1的位置並回傳 ## strrchr(S1, char c) - 從S1.size()-1開始尋找c在S1的位置並回傳該位置**指標** ## strspn(S1, S2) - 在S1尋找有幾個S2 ## strpbrk(S1, S2) - 從0開始找S1裡面有幾個S2 ___ # Class ## 一般的class - 分成protected\(僅允許繼承及內部使用)、private與public,差異在外部是否可以看到內值 - 若寫在private內,其實可以用\<class name>::\<variable name>要出來 - 要用的function也可以直接寫在class public裡面。 ### 程式碼 ```cpp= #include <iostream> #include <string> using namespace std; // 建構一個computer class class computer { public:// 可以從外部存取的函式 computer(); // constructor(建構子) 當一個class被建造並使用會被執行初始化的功能 void set_ab(); void print_word(); void print_ab(); private: // 只會存在class string word = "The word is defined in private."; int a; int b; }; // computer()這個constructor要幹嘛 computer::computer() { a = 30; b = 20; } void computer::set_ab() { int a, b; cout << "Pls enter a new value for a:"; cin >> a; computer::a = a; cout << "Pls enter a new value for b:"; cin >> b; computer::b = b; } void computer::print_word() { cout << "The word now is printed as follow:\n" << word << endl; } void computer::print_ab() { cout << "The value of a is: " << a << endl; cout << "The value of b is: " << b << endl; } int main() { computer test; // 印出現在word內的值 test.print_word();// The word is defined in private. test.print_ab();// 30、20 test.set_ab();// 輸入10, 20 test.print_ab();// 10 20 } ``` - 也可以把function整個寫在public/private裡面,會很亂就是了,不推薦。 ## structor - 分為`Destructor`、`Default constructor`、`Augmented constructor`和`Copy constructor` - 一般放在public裡面,好像跟封裝性以及繼承有關,如果知道其他用途可以放到private也OK ### Destructor - 用於解散、初始化建構子,可以釋放記憶體,暫時用不到,待補,詳見參考資料第六點[解構函式](#參考資料) ### Default constructor 如上程式碼,只能給予預設的值,如果要一開始就輸入開始值進去就要用augmented constructor ### Augmented constructor - 如果有給予初始值得需求,則可以使用這個建構子。 - 分為兩種,上面的比較好看,下面的在compile的時候比較有效率 - 初始化函數方式 ```cpp=18 computer::computer(int w, int h) { a = w; b = h; } ``` - 初始化列表(initialize list) - 我知道看起來超醜,看在他有效率的一面先饒了他吧... ```cpp=18 computer::computer(int w, int h) :a(w),b(h) { } ``` - initialize list甚至可以對const函數賦值 - 以下將對`const int heapSize`賦值 ```cpp= class MaxHeap { public: MaxHeap(); void insert_MaxHeaps(int); private: int heapSequence[10]; // 一個長度為9的Heap // heapSequence長度為10是因為heapSequence[0]不會使用 const int heapSize; int heapLength = 0; }; MaxHeap::MaxHeap() :heapSize(10) { for (int i = 0; i < heapSize; i++) { heapSequence[i] = 0; } } ``` ### Copy constructor - 還沒用到,待補 ## class 與 referance 和 pointer 在創立object時也可以用pointer 與 referance做命名,一樣會更動到原先object內部的值 ### 程式碼 ```cpp= #include <iostream> #include <string> using namespace std; // class 定義同上 int main() { computer test; computer* testPtr = &test; computer& testRef = test; // 所有對test testPtr testRef的操作都一樣 // 所有對test testPtr testRef的操作都會回到test上 } ``` ## operator overloading - 可以自己定義運算子(`=`、`'`...等)的用途,待補。詳見參考資料中第七點[operator overloading](#參考資料) ___ # include file ## 注意 - header file盡量不要使用using...... - header.h、source.cpp裡面不能出現main function。 - 在main function內include的方法。 ```cpp= include "computer.h" ``` - 在寫完檔案後記得存檔,VS不會在你要編譯檔案時自動儲存header.h和source.cpp。 - 在使用VS連結自己寫的header file 和 source file時要記得除了放在同一個資料夾以外還要經過外部連結設定才能使用 - 若在header內使用string,記得要include,並且加上`std::`。 - 在header內記得使用`ifndef`跟`define`。 - main.cpp內若不用iostream記得砍掉,快很多。 ## 一般寫法 ### Header.h ``` cpp= #pragma once #ifndef def_header #define def_header #include <string> // <object name>隨便取,不影響 class computer { public: computer(); void set_ab(); void set_word(); void print_word(); void print_ab(); void print_sum(); private: std::string word = "test"; int a = 0; int b = 0; }; #endif ``` ### source.cpp ```cpp= #include <iostream> #include <string> #include "Header.h" using namespace std; computer::computer() { a = 30; b = 20; word = ""; } void computer::set_ab() { cout << "Pls enter a new value for a: "; cin >> a; cout << "Pls enter a new value for b: "; cin >> b; } void computer::set_word() { cout << "What do you want to say ?" << endl; cin.ignore(); getline(cin, word); } void computer::print_word() { cout << "The word now is printed as follow:\n" << word << endl; } void computer::print_ab() { cout << "The value of a is: " << a << endl; cout << "The value of b is: " << b << endl; } void computer::print_sum() { cout << "The sum of a and b is: " << a + b << endl; } ``` ### main.cpp ```cpp= #include "Header.h" using namespace std; int main() { computer test; test.print_ab();// 30、20 test.print_word();// NULL test.print_sum();// 50 test.set_ab();// 輸入10, 20 test.set_word();// 輸入 所以 我到底怎麼數導被當掉的阿? test.print_ab();// 30、20 test.print_word();// 所以 我到底怎麼數導被當掉的阿? test.print_sum();// 30 } ``` ## 在header內使用預設值 ### 說明 - 這鬼東西超沒用,其實就是把一開始constructor在做的事情搶來做而已 - 有變化的就只有constructor而已,可以專注看constructor ### Header.h ```cpp= #pragma once #ifndef def_header #define def_header #include <string> // <object name>隨便取,不影響 class computer { public: computer(std::string = "", int = 30, int = 20); void set_ab(); void set_word(); void print_word(); void print_ab(); void print_sum(); private: std::string word ; int a ; int b ; }; #endif ``` ### source.cpp ```cpp= #include <iostream> #include <string> #include "Header.h" using namespace std; computer::computer(string x, int y, int z) { word = x; a = y; b = z; } void computer::set_ab() { cout << "Pls enter a new value for a: "; cin >> a; cout << "Pls enter a new value for b: "; cin >> b; } void computer::set_word() { cout << "What do you want to say ?" << endl; cin.ignore(); getline(cin, word); } void computer::print_word() { cout << "The word now is printed as follow:\n" << word << endl; } void computer::print_ab() { cout << "The value of a is: " << a << endl; cout << "The value of b is: " << b << endl; } void computer::print_sum() { cout << "The sum of a and b is: " << a + b << endl; } ``` ### main.cpp ```cpp= #include "Header.h" using namespace std; int main() { computer test; test.print_ab();// 30、20 test.print_word();// NULL test.print_sum();// 50 test.set_ab();// 輸入10, 20 test.set_word();// 輸入 所以 我到底怎麼數導被當掉的阿? test.print_ab();// 30、20 test.print_word();// 所以 我到底怎麼數導被當掉的阿? test.print_sum();// 30 } ``` ___ # 參考資料 1. 國立中央大學\(NCU)陳聿廣教授 2. [Yen-Chieh Sung](http://www.csie.ntu.edu.tw/~b01902011/) - material page 3. [stack參考資料](http://alrightchiu.github.io/SecondRound/stack-introjian-jie.html) 4. [蔡松仁教授開放式課程](https://ocw.nthu.edu.tw/ocw/index.php?page=course&cid=252) 5. [解構函式\(Desconstructor)](https://learn.microsoft.com/zh-tw/cpp/cpp/destructors-cpp?view=msvc-170) 6. [Operator overloading](https://learn.microsoft.com/zh-tw/cpp/cpp/operator-overloading?view=msvc-170) 7. [enumerate說明](https://shengyu7697.github.io/cpp-enum/) 8. [argc、argv參考資料](https://blog.gtwang.org/programming/c-cpp-tutorial-argc-argv-read-command-line-arguments/)