![](https://hackmd.io/_uploads/rkx6gvyAn.png) # 什麼是C/C++? * 跨平台語言 * Bjarne Stroustrup 開發 * 系統資源和內存高度控制 * 可移植性,應用在多個平台 * C++是C語言的延伸 * 函式導向 vs 物件導向 ## 怎麼編譯運行? 可以參照這一篇 https://hackmd.io/@Chunghao/rJBkfDQ1T --- ## C基礎語法 **針對基礎輸出輸入** ```c= #include <stdio.h> int main() { const int name = 20; printf("%d", name); return 0; } ``` > 1. #include <stdio.h>為C語言當中的標頭檔,表示輸出與輸入 > 2. printf or scanf 為C語言的輸出方法 > 3. 需要有修飾子進行資料型態判別 ### 修飾子 | - | + | %c | | -------- | -------- | -------- | | 向左靠齊 | 印出正負號 | 字元 | | %s | %d | %f | | -------- | -------- | -------- | | 字串 | 十進位整數 | 浮點數 | | %l | %u | %e | | -------- | -------- | -------- | | 長整數,加在d,u之前 | 無號 十進位整數 | 浮點數(指數) | :::danger C語言必須要使用,C++則沒有必要使用 ::: ## C++基礎語法 **針對基礎輸出輸入** ```cpp= #include <iostream> using namespace std; int main() { cout << "Hello World\n"; return 0; } ``` > 1. 這段程式碼是基礎語法中最常見的。 > 2. #include <iostream> 是指引入標準庫中的輸入跟輸出,為標頭檔。 > 3. using namespace std; std指得是逼準時是庫的命名空間。 > 4. cout 為輸出指令。 > 5. return 0 為回傳0給作業系統 **std:: 與 namespace std; 差別** ```cpp= #include <iostream> int main() { std::cout <<"Hello World" ; return 0; } ``` :::success > 1. using namespace std;拿掉 > 2. **std::** 語法上可以取代 ::: **\n 與 endl 差異** ```cpp= #include <iostream> int main() { std::cout << "Hello World " << std::endl; return 0; } ``` --- ## 變量 ```cpp= #include <iostream> #include <string> using namespace std; int main() { int name = 51; // 整數型態 = 2位元 = 可以在int前面 + unsigned or short or long float name2 = 5.2; // 浮點數 = 4位元 = 用於小數點 and 指數型態 double mane22 = 5.2; //被精度浮點數 = 8位元 = 用於小數點 and 指數型態 char name3 = 'F'; // 字元 = 1位元 = 儲存英文字母 and ASCII碼 string name4 = "project"; // 字串 = 4位元 = 表示一串話 bool name5 = true; //布林 = 1位元 = 用於判斷true or false cout << name << endl << name2 << endl << mane22 << endl << name3 << endl << name4 << endl << name5 << endl; return 0; } ``` > 此時輸出分別為**51, 5.2, 5.2, F, project, 1** ### 命名原則 * 不能使用關鍵字 * 前8為有效字元 * 可以使用英文字母,數字,底線 * 名稱中間不能有空白 * 第一個字元不可為數字 * 名稱要有意義,長短適中 * 大小寫有別 ### 常量 ```cpp= #include <iostream> using namespace std; int main() { const int name = 51; cout << name ; return 0; } ``` > 如果在int 前面新增一個const 代表這個值無法變動,如果再賦值給name的話就會報錯。 --- ## 跳脫字元 | \n | | -------- | | 換行 | | \f | \t | \b | | -------- | -------- | -------- | | 換頁 | 跳格 | 倒退 | | \" | \' | \/ | | -------- | -------- | -------- | | 雙引號 | 單引號 | 斜線 | | \\ | \x | \d | | -------- | -------- | -------- | | 反斜線 | ASCII(16進位) | ASCII(8進位) | ## 運算符 ### 算術運算子 | + | - | * | / | %(取餘數) | | -------- | -------- | -------- |-------- |-------- | | a+b | a-b | a*b |a/b |a%b | ### 關係運算子 | > | >= | < | <= | == | != |+=|-=|*=|/=|%=| | -------- | -------- | -------- |-------- | -------- | -------- |-------- |-------- |-------- |-------- |-------- | | 2>3 =false | 2>=3 =false | 2<3 =true |2<=3 =true | 2==3 =false | 2!=3 =true |a=a+b -> a+=b|a=a-b -> a-=b|a=a*b -> a*=b|a=a/b -> a/=b |a=a%b -> a%=b| ```cpp= #include <iostream> using namespace std; int main() { int x=1,y=2; cout << x+y << endl; cout << x-y << endl; cout << x*y << endl; cout << x/y << endl; x =1; //用於計算初始化,否則答案會報錯 cout << (x+=y) << endl; //3 x =1; cout << (x-=y) << endl; //-1 x =1; cout << (x*=y) << endl; //2 x =1; cout << (x/=y) << endl; //0 x =1; cout << (x%=y) << endl; //1 return 0; } ``` > C++運算輸出練習 --- ```c= #include <stdio.h> int main() { int x=1,y=2; printf("%d\n", x+y); printf("%d\n", x-y); printf("%d\n", x*y); printf("%d\n", x/y); x =1; //用於計算初始化,否則答案會報錯 printf("%d\n", (x+=y)); //3 x =1; printf("%d\n", (x-=y)); //-1 x =1; printf("%d\n", (x*=y)); //2 x =1; printf("%d\n", (x/=y)); //0 x =1; printf("%d\n", (x%=y)); //1 return 0; } ``` > C運算輸出練習 :::warning 可以看得出來C/C++語法上有些許上的差異。 ::: ### 邏輯運算子 | && | || | ! | | -------- | -------- | -------- | | AND or 且 | OR or 或 | NOT or 否 | ### 遞增/減運算子 | i++ | i- - | ++i | - -i | | -------- | -------- | -------- |-------- | | 表示先輸出i,再對i做出加法 | 表示先輸出i,再對i做出減法 | 先對i進行加法,再輸出i | 先對i進行減法,再輸出i --- ## 資料型態轉換 ```cpp= #include <iostream> #include <typeinfo> //轉換類型查看類型的標頭檔 using namespace std; int main() { int x = 5; double y = x; // 隱式轉換 double pi = 3.14159265359; int approxPi = static_cast<int>(pi); // 顯式轉換 double pi2 = 3.14159265359; int approxPi2 = (int)pi2; // C風格類型轉換 cout << typeid(approxPi2).name() << endl; return 0; } ``` > C++資料型態的轉換 ```c= #include <stdio.h> int main() { int x = 5; double y = 3.0; double result = x + y; //算數轉換 int x = 5; double y = (double)x; //指派轉換 double pi = 3.14159265359; int approxPi = (int)pi; //強制轉換,也叫做模式轉換 printf("%f\n", pi); return 0; } ``` > C資料型態的轉換 > C語言沒有查閱型別的函式庫 ## 數學運算 :::warning 1. C語言中使用:#include <math.h> 2. C++語言中使用:#include <cmath> ::: ```cpp= #include <iostream> #include <cmath> //C++數學函式庫 using namespace std; int main() { cout << max(5, 10) << endl; // 返回較大的數(最大值函數) cout << min(5, 10) << endl; // 返回較小的數(最小值函數) cout << sqrt(64) << endl; // 返回一個數的平方根 cout << round(2.6) << endl; // 四捨五入到最近的整數 cout << log(2) << endl; // 自然對數(以e為底的對數) cout << abs(5) << endl; // 返回一個整數的絕對值 cout << acos(0.5) << endl; // 返回一個數的反余弦(弧度) cout << asin(0.5) << endl; // 返回一個數的反正弦(弧度) cout << atan(5) << endl; // 返回一個數的反正切(弧度) cout << atan2(5, 3) << endl; // 返回兩個數的反正切(弧度) cout << ceil(5.6) << endl; // 向上取整數 cout << cos(5) << endl; // 返回一個數的余弦(弧度) cout << cosh(5) << endl; // 返回一個數的雙曲余弦 cout << exp(5) << endl; // 返回e的指數幂 cout << expm1(5) << endl; // 返回e的指數幂減去1 cout << fabs(-5) << endl; // 返回一個浮點數的绝對值 cout << fdim(5, 3) << endl; // 返回兩個數中較大的差值 cout << floor(5.6) << endl; // 向下取整數 cout << hypot(5, 3) << endl; // 返回兩個數的平方和的平方根 cout << fma(5, 3, 2) << endl; // 返回兩個數的乘積加上第三個數 cout << fmax(5, 3) << endl; // 返回兩個數中較大的數 cout << fmin(5, 3) << endl; // 返回兩個數中较小的數 cout << fmod(5, 3) << endl; // 返回兩個數相除的余數 cout << pow(5, 3) << endl; // 返回一個數的幂 cout << sin(5) << endl; // 返回一個數的正弦(弧度) cout << sinh(5) << endl; // 返回一個數的雙曲正弦 cout << tan(5) << endl; // 返回一個數的正切(弧度) cout << tanh(5) << endl; // 返回一個數的雙曲正切 return 0; } ``` **結果回傳:** ```cpp= max(5, 10)=10 min(5, 10)=5 sqrt(64)=8 round(2.6)=3 log(2)=0.693147 abs(5)=5 acos(0.5)=1.0472 asin(0.5)=0.523599 atan(5)=1.3734 atan2(5, 3)=1.03038 ceil(5.6)=6 cos(5)=0.283662 cosh(5)=74.2099 exp(5)=148.413 expm1(5)=147.413 fabs(-5)=5 fdim(5, 3)=2 floor(5.6)=5 hypot(5, 3)=5.83095 fma(5, 3, 2)=17 fmax(5, 3)=5 fmin(5, 3)=3 fmod(5, 3)=2 pow(5, 3)=125 sin(5)=-0.958924 sinh(5)=74.2032 tan(5)=-3.38052 tanh(5)=0.999909 ``` > C++撰寫數學函式庫 --- ```C= #include <stdio.h> #include <math.h> // C數學庫 #include <stdlib.h> //管理內存、随機數生成、字符串轉換、進程控制 int main() { int result; int x = 5, y = 10; result = (x > y) ? x : y; // 返回為較大的數 printf("max(5, 10) = %d\n", result); result = (x < y) ? x : y; // 返回較小的數 printf("min(5, 10) = %d\n", result); double sqrtValue = sqrt(64); // 返回一個數的平方根 printf("sqrt(64) = %lf\n", sqrtValue); double roundValue = round(2.6); // 四捨五入到最近的的整數 printf("round(2.6) = %lf\n", roundValue); double logValue = log(2); // 自然對數(以e為底的對數) printf("log(2) = %lf\n", logValue); int absValue = abs(5); // 返回一個整數的绝對值 printf("abs(5) = %d\n", absValue); double acosValue = acos(0.5); // 返回一個數的反余弦(弧度) printf("acos(0.5) = %lf\n", acosValue); double asinValue = asin(0.5); // 返回一個數的反正弦(弧度) printf("asin(0.5) = %lf\n", asinValue); double atanValue = atan(5); // 返回一個數的反正切(弧度) printf("atan(5) = %lf\n", atanValue); double atan2Value = atan2(5, 3); // 返回兩個數的反正切(弧度) printf("atan2(5, 3) = %lf\n", atan2Value); double ceilValue = ceil(5.6); // 向上取整數 printf("ceil(5.6) = %lf\n", ceilValue); double cosValue = cos(5); // 返回一個數的余弦(弧度) printf("cos(5) = %lf\n", cosValue); double coshValue = cosh(5); // 返回一個數的雙曲余弦 printf("cosh(5) = %lf\n", coshValue); double expValue = exp(5); // 返回e的指數幂 printf("exp(5) = %lf\n", expValue); double expm1Value = expm1(5); // 返回e的指數幂減去1 printf("expm1(5) = %lf\n", expm1Value); double fabsValue = abs(-5); // 返回一個浮點數的绝對值 printf("abs(-5) = %lf\n", fabsValue); double fdimValue = fdim(5, 3); // 返回兩個數中較大的差值 printf("fdim(5, 3) = %lf\n", fdimValue); double floorValue = floor(5.6); // 向下取整數 printf("floor(5.6) = %lf\n", floorValue); double hypotValue = hypot(5, 3); // 返回兩個數的平方和的平方根 printf("hypot(5, 3) = %lf\n", hypotValue); double fmaValue = fma(5, 3, 2); // 返回兩個數的乘積加上第三個數 printf("fma(5, 3, 2) = %lf\n", fmaValue); double fmaxValue = fmax(5, 3); // 返回兩個數中較大的數 printf("fmax(5, 3) = %lf\n", fmaxValue); double fminValue = fmin(5, 3); // 返回兩個數中較小的數 printf("fmin(5, 3) = %lf\n", fminValue); double fmodValue = fmod(5, 3); // 返回兩個數相除的餘數 printf("fmod(5, 3) = %lf\n", fmodValue); double powValue = pow(5, 3); // 返回一個數的幂 printf("pow(5, 3) = %lf\n", powValue); double sinValue = sin(5); // 返回一個數的正弦(弧度) printf("sin(5) = %lf\n", sinValue); double sinhValue = sinh(5); // 返回一個數的雙曲正弦 printf("sinh(5) = %lf\n", sinhValue); double tanValue = tan(5); // 返回一個數的正切(弧度) printf("tan(5) = %lf\n", tanValue); double tanhValue = tanh(5); // 返回一個數的雙曲正切 printf("tanh(5) = %lf\n", tanhValue); return 0; } ``` **結果回傳:** ```c= max(5, 10) = 10 min(5, 10) = 5 sqrt(64) = 8.000000 round(2.6) = 3.000000 log(2) = 0.693147 abs(5) = 5 acos(0.5) = 1.047198 asin(0.5) = 0.523599 atan(5) = 1.373401 atan2(5, 3) = 1.030377 ceil(5.6) = 6.000000 cos(5) = 0.283662 cosh(5) = 74.209949 exp(5) = 148.413159 expm1(5) = 147.413159 abs(-5) = 5.000000 fdim(5, 3) = 2.000000 floor(5.6) = 5.000000 hypot(5, 3) = 5.830952 fma(5, 3, 2) = 17.000000 fmax(5, 3) = 5.000000 fmin(5, 3) = 3.000000 fmod(5, 3) = 2.000000 pow(5, 3) = 125.000000 sin(5) = -0.958924 sinh(5) = 74.203211 tan(5) = -3.380515 tanh(5) = 0.999909 ``` > C撰寫數學函式庫 :::info C語言沒有max,min的函數,因此要使用這種比大小方法回傳最大值。 ```c= result = (x > y) ? x : y; // 返回為較大的數 printf("max(5, 10) = %d\n", result); ``` ::: --- ## **#define**是什麼? :::success * C語言能用的,C++都可以做使用。 * 宏定義命令,由以下規範所組成 :+1: * 簡單的宏定義如下: ```cpp #define <宏名> <字符串> ``` * 帶有參數的宏定義: ```cpp #define <宏名> (<參數表>) <宏體> ``` ::: 1. 簡單的宏定義: ```cpp= #include <iostream> using namespace std; #define PI 3.14 int main(){ double radius; cout << "請輸入半徑:"; cin >> radius; double area = PI * radius * radius; double circumference = 2 * PI * radius; cout << "圖的面積是:" << area << endl; cout << "圖的周長是:" << circumference << endl; return 0; } ``` :::warning > 1. 這個意思是指定義一個簡單的宏定義PI的值為3.14,因此在main當中調用PI就可以代表3.14這個數值。 > 2. Ans: 請輸入半徑:2 圖的面積是:12.56 圖的周長是:12.56 ::: 2. 帶有參數的宏定義: ```cpp= #include <iostream> using namespace std; #define SQUARE(x) ((x) * (x)) int main() { int num = 5; int squared = SQUARE(num); cout << "數字 " << num << " 的平方是 " << squared << endl; return 0; } ``` :::warning > 1. 這個意思是指定義一個帶有參數的宏定義SQUARE,其參數x的方法為x*x,在main當中宣告num = 5,帶入SQUARE的方法,再將結果賦值給squared。 > 2. Ans:數字5的平方是25 ::: --- ## 條件語句 ### 1. if/else * C語言: ```c= #include <stdio.h> int main() { int number; printf("enter an integer:"); scanf("%d",&number); if (number > 0) { printf("The number is positive.\n"); } else if (number < 0) { printf("The number is negative.\n"); } else { printf("The number is zero.\n"); } return 0; } ``` :::success * 這邊使用到條件式,**&number**這個用法代表把值帶入number。 ::: ```c= #include <stdio.h> int main() { for (int i = 0; i < 5; i++) { for (int j = i + 1; j > 0; j--) { printf("*"); } printf("\n"); } return 0; } ``` ```c * ** *** **** ***** ``` :::success i=層數, j=*數,C++基本上只有輸出入的部分改掉。 ::: * C++語言: ```cpp= #include <iostream> int main() { int number; std::cout << "Enter an integer: "; std::cin >> number; if (number > 0) { std::cout << "The number is positive." << std::endl; } else if (number < 0) { std::cout << "The number is negative." << std::endl; } else { std::cout << "The number is zero." << std::endl; } return 0; } ``` :::warning * 這邊使用 " cin >> number" 把值帶入number,基本上與C大同小異。 ::: :::success * 值得一提的是C++語法當中有一個有趣的寫法(Cpp專屬條件表達式,雜項運算符),如下: ```cpp= #include <iostream> using namespace std; int main() { int number = 20; string result = (number < 18) ? "goodmorning":"hi"; cout << result << endl; return 0; } ``` * :zap: Condition ? X : Y ```cpp string result = (number < 18) ? "goodmorning":"hi"; ``` ::: --- ### 2. switch case * C語言: ```c= #include <stdio.h> int main() { int choice; printf("選擇(1, 2, 3, 4):"); scanf("%d", &choice); switch (choice) { case 1: printf("你選了 1\n"); break; case 2: printf("你選了 2\n"); break; case 3: printf("你選了 3\n"); break; case 4: printf("你選了 4\n"); break; default: printf("無效\n"); } return 0; } ``` * C++語言: ```cpp= #include <iostream> using namespace std; int main() { int choice; cout << "選擇(1, 2, 3, 4):"; cin >> choice; switch (choice) { case 1: cout << "你選擇了 1" << endl; break; case 2: cout << "你選擇了 2" << endl; break; case 3: cout << "你選擇了 3" << endl; break; case 4: cout << "你選擇了 4" << endl; break; default: cout << "無效" << endl; } return 0; } ``` ### 3. While-do * C語言: ```c= #include <stdio.h> int main() { int number = 2; while (1) { if (number > 0) { printf("The number is positive.\n"); } else if (number < 0) { printf("The number is negative.\n"); } else { printf("The number is zero.\n"); } break; } return 0; } ``` * C++語言: ```cpp= #include <iostream> using namespace std; int main() { int number = 2; while (true) { if (number > 0) { cout << "The number is positive." << endl; } else if (number < 0) { cout << "The number is negative." << endl; } else { cout << "The number is zero." << endl; } break; } return 0; } ``` :::info **while(ture)** or **while(1)**,都代表為真的意思,都會執行無限迴圈。 ::: --- ## 陣列 * C語言: ```c= #include <stdio.h> #include <string.h> int main() { char timer[][15] = {"jack", "chris", "anderson", "kevin"}; printf("%s\n", timer[2]); return 0; } ``` :::info * 這邊代表定義一個timer二維陣列,每個陣列的數組限制大小為15,從0開始數到2,其輸出為**anderson** * 值得注意的是,C語言當中,並沒有**string**的用法,字串使用**char** ::: * C++語言: ```cpp= #include <iostream> using namespace std; int main() { string timer [] ={"jack","chris","anderson","kevin"}; cout << timer[2] <<endl; return 0; } ``` --- ## Function > 1. 介紹 > 2. 宣告 > 3. 函式中的參數 > 4. 變數的範圍 > 5. 靜態變數 #### 介紹 > 一段程式碼,執行特別的工作。 > 可重複使用 > 讓程式變得淺顯易懂 > 在呼叫函式不變的狀況下,可以直接修改程式。 #### 宣告 ```cpp 回傳值型態 函式名稱 (參數) ``` * 沒有回傳值:void square(int length) ```c= #include <stdio.h> void square(int length); //宣告function 沒有回傳值 void square(int length){ //撰寫function內容 } int main(){ square(); //傳入square function的參數 } ``` * 有回傳值:int square(int len) ```c= #include <stdio.h> int square(int length); //宣告function int square(int length){ int x =0; x = length * length; //function內執行的程式碼 return x; } int main(){ int len = 5; int ans; ans = square(len); //主function中len的值帶入square function printf("square = %d\n",ans); return 0; } ``` * Function中的參數 ```c= #include <stdio.h> // 函式原型(宣告),宣告時只需要指定型態即可 int sum(int, int); int main() { int num1 = 5, num2 = 6; // 設定兩個數字 int ans; // 答案存入ans中 ans = sum(num1, num2); // 傳入sum函式的參數有兩個(5, 6) printf("sum = %d\n", ans); return 0; } // 定義函式,有兩個 int sum(int a, int b) { int x = 0; // 將答案存入x中 x = a + b; return x; // 將答案傳回主程式 } ``` * 變數的範圍 > 1. global (全域變數)整個程式中皆可以使用此變數 > 2. local (區域變數)只能在部分函式中使用 > 範例如下: ```c= #include <stdio.h> int global1 = 0; // 全域變數 int main() { int local1 = 2, local2 = 3; // 區域變數 global1 = local1 + local2; printf("%d \n", global1); /* 5 */ return 0; } ``` * 靜態變數(Static Variable) > 1. static變數,是一個區域變數,但不會因為函式執行結束,變數內的資料就不見。 ```c= #include <stdio.h> void hello(); void hello(){ static int x = 0; printf("hello world: %d\n",x); x++; } int main(){ for(int i = 0; i < 5; i++){ hello(); } return 0; } ``` > 上面的for迴圈,是為了要進入此函式五次才設定的。函式內部的X沒有因為離開函式後,其數字重新歸零,而是繼續累加。這就是static變數的最大特色。要等到程式全部結束後,X才會回到原本預設的狀態。 --- ## 指標 pointer :::info 指標是用來儲存"**記憶體位址**"的變數,設計師可以透過指標來管理記憶體,包含:**配置**,**存值**,**取值**,**釋放**。 ::: > 1. & : 取得已存在的變數位址 > 2. * : 表示為指標變數 > 3. new : 配置指定型別的記憶體位址 > 4. 另一個指標:將已經存在的指標所儲存的記憶體位址指派給另一個指標 ### 宣告 ```cpp= type* name; // *就代表指標 這個指標為name type* name = address; type* nameA,* nameB; ``` * 基本存取功能 ```cpp= #include <iostream> using namespace std; int main(){ int a ; a = 8; cout << a << endl; int * p; // 建立一個指標 p的變數,裡面存放一個記憶體位址 p = &a; // 這邊指向記憶體a cout << p << endl; //因此得出p裡面裝得是a的記憶體位址 *p = 10; // 這邊是用來管理記憶體位址裡的值, 這邊將p記憶體位址裡的值變成10 cout << *p << endl; // 因此裡面的值會改成10 cout << a << endl; // 由於p是指向a的記憶體位址,因此裡面的值也會改成10 return 0; } ``` * new 的用法 ```cpp= int * r; r = new int; //另外派一個空間給r *r =100; //管理空間裡的值 cout << r << endl; //得到r的位址 cout << *r << endl; //得到該位址中的值 return 0; ``` * 另一個指標 的用法 ```cpp= int * r; r = new int; //另外派一個空間給r * r =100; //管理空間裡的值 cout << r << endl; //得到r的位址 cout << *r << endl; //得到該位址中的值 int * s = r; //建立一個指標s 存放r的記憶體位址 * s =200; //管理該記憶體中的值改為200 cout << * r << endl; //輸出後值為200 return 0; ``` ### delete 用法 > 1. 釋放記憶體位址 > 2. 用 new 配置給指標的記憶體可以用delete釋放 ```cpp= int * r; r = new int; *r =100; cout << r << endl; //得到r的位址 cout << *r << endl; //得到該位址中的值 int * s = r; // 建立一個指標s 存放r的記憶體位址 * s =200; //管理該記憶體中的值改為200 cout << * r << endl; //輸出後值為200 delete r; // 把該位址的空間砍掉 cout << r << endl; // 0x12d606ac0 cout << * r << endl; // 0 cout << s << endl; //0x12d606ac0 cout << * s << endl; // 0 return 0; ``` ### const 用法 > 1. 限制指標or指標所管理的記憶體為 read-only > 2. type * const name; > 3. const type * name; ```cpp= int * const m = new int ; *m =100; *m =200; cout << *m <<endl; //200 ``` * 如果這邊再寫delete釋放掉m的位址 #### type * const name; ```cpp= int * const m = new int ; //配了一個新的位址給m *m =100; //指標管理裡面的值 *m =200; //可以二次更改裡面的值 cout << *m <<endl; delete m; m = new int ; return 0; ``` :::warning ``` error: cannot assign to variable 'm' with const-qualified type 'int *const' ``` > 因此可得出const 只可讀取 ::: #### const type * name; ```cpp= int * const m = new int ; //配了一個新的位址給m *m =100; //指標管理裡面的值 *m =200; //可以二次更改裡面的值 cout << *m <<endl; const int * n = new int ; //給予新的位址 *n=100; //將*n的值給為100 cout << *n <<endl; return 0; ``` :::warning ``` error: read-only variable is not assignable ``` > 這樣寫n還沒定義值就先報錯無改給值,你可以得很奇怪,因此這邊不能這樣賦予他一個新的記憶體空間。 ::: ```cpp= int * const m = new int ; //配了一個新的位址給m *m =100; //指標管理裡面的值 *m =200; //可以二次更改裡面的值 cout << *m <<endl; const int * n = m ; //將位址指向m cout << *n <<endl; //因此可以得出與m相同的值 return 0; ``` ### 指標參數 > 1. 以指標為參數 pass by pointer > 2. 呼叫function > 3. pass by value > 4. pass by point * main3.h ```cpp= #include <iostream> using namespace std; void showValue(int * p); void showValue(int * p){ cout << *p << endl; } ``` * main2.cpp ```cpp= # include <iostream> using namespace std; #include "main3.h" int main(){ int a = 10; showValue(&a); //10 int * b = new int ; *b = 20; showValue(b); //20 return 0; } ``` * 解釋 ![](https://hackmd.io/_uploads/SyKiNlQ0h.png) --- #### 為何Value,&Value輸出結果不一樣? * main3.h ```cpp= #include <iostream> using namespace std; void passbyValue(int Value); void passbyPoint(int * pValue); void passbyValue(int Value){ Value += 100; } void passbyPoint(int * pValue){ *pValue += 100; } ``` * main2.cpp ```cpp= # include <iostream> using namespace std; #include "main3.h" int main(){ int Value =1; passbyValue(Value); cout << Value << endl; //1 passbyPoint(&Value); cout << Value << endl; //101 return 0; } ``` > 解釋第一部分為何輸出1 ![](https://hackmd.io/_uploads/BJqFoe7A2.png) > 解釋第二部分為何輸出=101 ![](https://hackmd.io/_uploads/H1Qm3x7Ch.png) --- ### return 型別為指標 > 呼叫敘述是一個記憶體位址 > 不應return 區域變數的記憶體位址 > 可以宣告為const * main3.h ```cpp= #include <iostream> using namespace std; int * getAddressA(){ int * p = new int ; // 新增一個記憶體位址 * p =100; // 記憶體位址中存在的值 return p; // return一個記憶體位址 } int * getAddressB(){ return new int ; //新增一個記憶體位址 } int * getAddressC( const int * p){ //以p為主本 int * q = new int ; //建立一個記憶體位址q *q = *p; // 賦值 *q += 100; //修改q的值 return q; //返回q } ``` * main2.cpp ```cpp= # include <iostream> using namespace std; #include "main3.h" int main(){ int * i = getAddressA(); // getAddressA 是一個記憶體位址 cout << * i << endl; // 這邊代表取值, int * j = getAddressB(); //代表一個記憶體位址 * j = 200; //設定值為200 cout << *j << endl; //輸出即刻為200 int *m = new int; // 新增一個記憶體位址 * m = 1; // 記憶體位址內值為1 int * n = getAddressC(m); // 新增一個記憶體位址n,調用getAddressC函式,參數m cout << *n << endl; return 0; } ``` --- ### 指標的指標 > 1. 宣告 type** name; > 2. 存取值 **name; ```cpp= #include <iostream> using namespace std; int main(){ int ** a; a = new int *; //指標的記憶體位址 * a = new int; // 儲存可以放int型別的值的記憶體位址 ** a =10; // 存放值 cout << a << endl; // 記憶體位址 cout << * a << endl; // 記憶體位址 cout << ** a << endl; // 10 int * b = new int; *b = 20; a = &b; cout << ** a << endl; // 20 } ``` ### void * > 1. 指派 > 2. casting ```cpp= int * b = new int; *b = 20; a = &b; cout << ** a << endl; // 20 void * v; v = b; cout << b << endl; cout << v << endl; cout << *b << endl; // 錯誤訊息 cout << *v << endl; // 錯誤訊息 因為void 是通用型型別 無法確定型別是什麼,因此無法輸出 return 0; ``` :::warning * 解決辦法 ```cpp= int * b = new int; *b = 20; a = &b; cout << ** a << endl; // 20 void * v; v = b; cout << b << endl; cout << v << endl; cout << *((int*)b) << endl; // casting cout << *((int*)v) << endl; // casting return 0; ``` ::: ### 指標陣列 > 1. 宣告 > 2. 存取 ```cpp= #include <iostream> using namespace std; int main(){ int * array[10]; // 新增一個指標陣列 for( int i = 0; i < 10; i++){ array[i] = new int; //初始化並新增一個陣列記憶體位址 *array[i] = i + 1; } for( int i = 0 ; i < 10 ; i++){ cout << *array[i] << endl; } return 0; } ``` - [:negative_squared_cross_mark: ] 動態指標陣列 # 物件導向 ## 物件 * 何謂物件? > 執行環境依照類別中的宣告,所配置的記憶體群組。它可以儲存一群資料,而該群資料可以完整的描述一個特定的運算單位。例如:一群可以完整描述一張訂單的資料、一群可以完整描述購買者的資料、一群可以完整描述一件商品的資料、一群可以完整描述日期時間的資料、一群可以完整描述信用卡付款的資料...。 > 也就是說:一個記憶體群組,代表一個特定運算單位的完整資料。這一個記憶體群組,我們就稱之為物件。 > 所以就程式語言的角度上也可以說:物件一群記憶體的集合。 > 物件擁有什麼 資料成員(Data Members) => 儲存資料(變數)。 很多文件的解說中稱之為屬性或狀態。在 Java 中稱之為欄位。 > 成員函式 (Member Functions) => 運算資料。 很多文件的解說中稱之為行為或能力。在 Java 中稱之為方法。 * 為什麼要使用物件導向 在物件導向之前是函式導向。隨著運算複雜度的提升,各語言也逐一的支援物件導向。物件導向與函式導向的基本差異是:物件儲存資料,物件運算資料。 * 以 C / C++ 語言為例,在函式導向時期(C 語言時期),雖然可以用結構(struct)宣告一個新型別,集合一群資料。但是,那一群資料本身並不具有運算能力,它只能當參數讓函式運算。所以,資料與運算資料的函式是沒有關係的。 * 到了物件導向時期(C++ 時期),改用類別(class)來宣告新型別。依照類別的宣告建立的物件,除了是一群資料的集合之外,本身也具有運算的能力。也就是說:資料與運算資料的函式是屬於同一個物件的成員。 * 相同類別的物件,一定擁有相同的成員 相同名稱的資料成員,但它的值不見得一樣。 相同名稱的成員函式,但它運算的結果不一定一樣。 每一個物件獨立管理與運算自己的資料 除非特殊的設計需求。基本上,每個物件運算自己的資料。 ## 函式導向 & 物件導向 差異 * 函式導向 ```cpp= //函式導向,函式是老大 struct boot{ int redius; int height; double girth; double area; double volume; }; double getGirth(struct boot c); //結構指的是接受一群資料做運算 ``` * 物件導向 ```cpp= // 物件導向,物件是老大,物件擁有資料,且擁有運算能力 class Circle{ public: //存取限制一樣 int redius; int height; double girth; double area; double volume; double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } }; ``` * 執行物件導向 ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; cout << c1.getGirth() << endl; Circle c2; c2.redius = 10; cout << c2.getGirth() << endl; return 0; } ``` * 總結 > 1. 物件儲存資料,運送資料 > 2. 物件導向不能用靜態觀點,不可看單一程式碼,要看真的主函式中真正配置的記憶體位址 > 3. 環境依照類別做出來物件,類別是說明書,材料是記憶體,配出來的記憶體是物件 ## 類別 * 什麼是類別 > 像 int 一樣,是 C++ 中合法的型別。 * 為什麼要開發類別 > 因為程式有物件的需求,所以依照物件的需求開發類別 * 類別用來做什麼 > 宣告變數 宣告指標 宣告參考 物件轉型 物件識別 執行環境製做物件的說明書 * 類別中有什麼 > 物件成員=> 物件資料成員,物件成員函式 類別成員=> 類別資料成員,類別成員函式 建構函式(建構子) 其他 ```cpp= /* 1.類別中全部叫做物件成員 2.class建立了一個Circle類別 3.宣告五個變數 = 物件資料成員 4.宣告一個函式 = 成員函式 */ class Circle{ //Circle 類別 public: // 存取限制 int redius; // 物件資料成員 int height; // 物件資料成員 double girth; // 物件資料成員 double area; // 物件資料成員 double volume; // 物件資料成員 // 成員函式 double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } }; ``` ## 物件變數 * 宣告 > ClassName objectName; > 變數宣告時,環境會依照類別中的宣告來建立物件。並把物件的記憶體位址指派給變數。 ```cpp= class Circle{ public: //存取限制一樣 int redius; int height; double girth; double area; double volume; double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } }; ``` ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; cout << c1.getGirth() << endl; Circle c2; c2.redius = 10; cout << c2.getGirth() << endl; return 0; } ``` * 講解記憶體變化 > 標黃色代表他們是一體的,記憶體一定是一格一格的,不是一群物件,是一群記憶體,以群為單位配送記體位址複製給c1 ![](https://hackmd.io/_uploads/Syu9zXLC3.png) > 到這裡,執行main函式,radius記憶體位址變數變成10,並且執行getGirth,再將結果複製給0x123(c1) ![](https://hackmd.io/_uploads/rk4MNmIRn.png) > 接著main函式當中,執行第二個c2,為何執行第二個c2,原本的記憶體位址不會消失呢?由下圖解釋: ![](https://hackmd.io/_uploads/SkxobzPA3.png) * 成員存取 > objectName.dataMember objectName.memberFunction() ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; // objectName.dataMember cout << c1.getGirth() << endl; // objectName.memberFunction() Circle c2; c2.redius = 10; cout << c2.getGirth() << endl; return 0; } ``` > 用 變數.成員 的方式,存取物件成員。 * 指派 > objectName = otherObjectName; ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; cout << c1.getGirth() << endl; // 62.8318 Circle c2; c2.redius = 20; cout << c2.getGirth() << endl; // 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 cout << "---------------" << endl; c1 = c2; cout << c1.getGirth() << endl; // 此時的c1輸出結果 = 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 return 0; } ``` > 變數和物件是挷定的,也就是說這個變數不能再指派另一個物件的記憶體位址給它。指派時是將 '=' 右邊的物件的資料成員的值,複製給 '=' 左邊的物件的資料成員。 * 物件變數參數 > 函式原型 : void function(ClassName objectName) 呼叫敍述 : function(objectName); > 在函式呼叫敍述的小括號中放物件變數時,是把本物件的成員變數的值,複製給函式的物件變數參數。 ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; cout << c1.getGirth() << endl; // 62.8318 Circle c2; c2.redius = 20; cout << c2.getGirth() << endl; // 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 cout << "---------------" << endl; c1 = c2; cout << c1.getGirth() << endl; // 此時的c1輸出結果 = 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 cout << "---------------" << endl; int i = c1.compare(c2); // c2變成參數傳給compare if( i == 0){ cout << "valus are the same" << endl; }if else( i > 0){ cout << "c1 is bigger" << endl; }else{ cout <, "c2 is bigger" << endl; } return 0; } ``` ```cpp= // 物件導向,物件是老大,物件擁有資料,定且擁有運算能力 class Circle{ public: //存取限制一樣 int redius; int height; double girth; double area; double volume; double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } int compare(Circle c){ // void function(ClassName objectName) if( redius > c.redius){ return 1; }else if( redius < c.redius){ return -1; }else{ return 0; } } }; ``` * 用圖解釋記憶體變化 > 1. int compare(Circle c) : > 2. c1.compare(c2) : 在c1中執行compare,所以將其記憶體位建立在c1中,並將物件的值指派一份給c > 3. c2物件的值指派給c的值 > 4. 接著改變c2的值就會改變c.radius的值 > 5. c2的值不會被改變,他是複製一份給c,並指派參數給c.radius,如果改變c.radius的值,c2依然為20 ![](https://hackmd.io/_uploads/BJc-tzPAn.png) * 物件變數返回值 > 函式原型 : ClassName function() 呼叫敍述 : ClassName objectName = function(); ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.redius = 10; cout << c1.getGirth() << endl; // 62.8318 Circle c2; c2.redius = 20; cout << c2.getGirth() << endl; // 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 cout << "---------------" << endl; c1 = c2; cout << c1.getGirth() << endl; // 此時的c1輸出結果 = 125.664 cout << "c1 = " << &c1 << endl; // c1 = 0x16d63b340 cout << "c2 = " << &c2 << endl; // c2 = 0x16d63b320 cout << "---------------" << endl; int i = c1.compare(c2); if( i == 0){ cout << "valus are the same" << endl; }else if( i > 0){ cout << "c1 is bigger" << endl; }else{ cout << "c2 is bigger" << endl; } cout << c2.getGirth() << endl; cout << "---------------" << endl; Circle c3 = c2.copy(); //用類別作為返回型別 cout << c3.getGirth() << endl; // 125.664 return 0; } ``` ```cpp= // 物件導向,物件是老大,物件擁有資料,定且擁有運算能力 class Circle{ public: //存取限制一樣 int redius; int height; double girth; double area; double volume; double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } int compare(Circle c){ if( redius > c.redius){ return 1; }else if( redius < c.redius){ return -1; }else{ return 0; } } Circle copy(){ Circle c; c.redius = redius; return c; } }; ``` > 代表返回值是這個類別的物件變數 > 不過這樣有個壞處,這個寫法會多佔用一個記憶體位址,如果是大型運算會佔太多不必要的空間 ## 物件指標 * 宣告 :::info > ClassName * pointerName; Or ClassName * pointerName = new ClassName; ::: * 建立物件 :::warning > new ClassName new ClassName() ::: ```cpp= class Circle{ public: //存取限制一樣 int redius; int height; double girth; double area; double volume; double getGirth(){ //定義,運算自己的資料 , 物件的函式運算自己的資料 return redius * 2 * 3.14159; } int compare(Circle c){ if( redius > c.redius){ return 1; }else if( redius < c.redius){ return -1; }else{ return 0; } } Circle copy(){ Circle c; c.redius = redius; return c; } }; ``` ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle * c1; Circle * c2 = new Circle; // 合法宣告、建立物件 c1 = new Circle(); //合法宣告、建立物件 cout << c1 << endl; cout << c2 << endl; return 0; } ``` > 這邊代表新增了兩個物件分別創建出一個記憶體位址 * 指派 > pointerName = memory address; :::danger > Ex: pointerName = new ClassName; Or pointerName = &objectName; Or pointerName = otherPointerName; ::: ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle * pc1; Circle * pc2 = new Circle; pc1 = new Circle(); cout << pc1 << endl; // 0x136e068d0 cout << pc2 << endl; // 0x136e068b0 cout << "------------------" << endl; delete pc2; // 釋放記憶體 pc1 = pc2; // 重新指派 cout << pc1 << endl; // 0x136e068b0 cout << pc2 << endl; // 0x136e068b0 cout << "------------------" << endl; Circle c; Circle * pc3 = &cc; cout << pc3 << endl; // 0x16fd5b338 cout << &c << endl; // 0x16fd5b338 return 0; } ``` * 圖表解釋 ![](https://hackmd.io/_uploads/BJ5SJUuA3.png) * 成員存取 > pointerName -> dataMember pointerName -> memberFunction() :::warning > 用 指標 -> 成員 的方式,存取物件成員。 ::: ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle * pc1 = new Circle(); pc1 -> redius = 10; // 指標透過 -> 選取資料成員 cout << pc1 -> getGirth() << endl; //指標透過 -> 呼叫成員函式 return 0; } ``` * 物件指標參數 :::warning > 函式原型 : void function(ClassName* pointer) 呼叫敍述 : function(memory address) ::: * 物件指標返回值 :::info > 函式原型 : ClassName * function() 呼叫敍述 : ClassName * pointer = function(); ::: --- ## 抽象 - [ :negative_squared_cross_mark:] 持續更新 --- ## 封裝 > 物件導向中用來實作資訊隱藏的機制,確保物件的安全。其作法為:隱藏不想讓外界碰觸的成員,只公開接受外界存取的成員。 一般而言,類別開發者為了物件的安全,會把資料成員全部隱藏起來,只公開存取或運算資料成員的函式成員。讓物件資料的修改,完全由函式成員掌控其值的變化,避免物件產生預期外的值。 成員存取的控制以存取修飾詞宣告的段落為單位。在宣告某一個存取修飾詞之後,另一個存取修飾詞出現之前為一個段落。若都沒有宣告,預設為 private 。 * 存取修飾詞: > 1.private :只允許本類別中的其他成員存取。 > 2.protected :允許本類別的子類別存取。 > 3.public :允許所有類別存取。 ```cpp= #define PI 3.14159 class Circle{ private: int radius; int height; public: double getGirth(); double getArea(); double getVolume(); void setRadius(int r); void setHeight(int h); }; double Circle :: getGirth(){ return radius * 2 * PI; } double Circle :: getArea(){ return radius * radius * PI; } double Circle :: getVolume(){ return getArea() * height; } void Circle :: setRadius(int r){ if(r >= 1 && r<= 1000){ radius = r; } } void Circle :: setHeight(int h){ if(h >= 1 && h<= 100){ radius = h; } } ``` ```cpp= #include <iostream> using namespace std; #include "Circle.h" int main(){ Circle c1; c1.setRadius(10); c1.setHeight(5); cout << c1.getArea() << endl; } ``` --- ## 繼承 > 物件導向中用來避免程式碼重複撰寫與減低維護困難度的機制。子類別可以繼承父類別中的所有成員。也就是說,把多個類別都會用到的成員,寫在父類別中,子類別只要繼承父類別,不必再寫,就可以擁有那群成員。不但避免了程式寫的重複撰寫,也減少了日後維護的困難度。因為若有程式碼要修改,只需要修改一個類別。 > 當我們寫一個新類別,指定繼承某一個或多個己存在的類別時,就是在使用那一個或多個己存在的類別。新類別稱之為衍生類別 (Derived class) 或子類別 (Child class),己存在的類別稱之為基礎類別 (Base class) 或父類別 (Parent class)。子類別繼承父類別中的所有成員。但繼承了不代表可以存取,子類別不能存取父類別中宣告為 private 的成員,只能存取宣告為 protected 或 public 的成員。 > 當你是類別開發者時,不接受子類別與物件存取的,宣告為 private。不接受物件存取,但接受子類別存取的,宣告為 protected。接受物件存取的才宣告為 public。 ```cpp= #include <iostream> using namespace std; #include "myheader.h" int main(){ Circle c1; cout << c1.getArea() << endl; cout << c1.getGirth() << endl; return 0; } ``` ```cpp= class Shape{ int area; //成員變數 int girth; public: Shape(){ //建構函式 area = 0; girth = 0; } int getArea(); //成員函數 int getGirth(); }; int Shape ::getArea(){ //定義成員函式 return area; } int Shape ::getGirth(){ return girth; } class Circle : public Shape{ //子類別Circle(下層)繼承父類別Shape(上層) }; ``` * 繼承運算符號 : * 繼承是為了在父類別的基礎之上,做進一步的開發。所以繼承不是重點,重點是繼承後的子類別可以做什麼? * 子類別中可以: 1. 新增子類別的成員 2. 在子類別中可以新增父類別中沒有宣告的成員。 > 隱藏父類別的成員 在子類別中可以宣告父類中己宣告過的成員,新宣告的成員會遮蔽父類別中相同名稱的成員。 若子類別中宣告與父類別中名稱相同的資料成員,子類別中的函式存取的是子類別中的資料成員。但父類別中的函式存取的是父類別中的資料成員。 > 若子類別中宣告與父類別名稱相同但參數列不同的函式,不是 Overloading,一樣是遮蔽了父類別的成員函式。 ```cpp= #include <iostream> using namespace std; #include "myheader.h" int main(){ Circle c1; c1.setRedius(10); cout << c1.getArea()<< endl; cout << c1.getGirth() << endl; cout << "-----------------" << endl; return 0; } ``` ```cpp= #define PI 3.14159 class Shape{ protected: //為了讓子類可以改變父類中的成員函數 int area; //成員函數 int girth; public: Shape(){ // 建構函式 area = 0; girth = 0; } int getArea(); int getGirth(); }; int Shape ::getArea(){ //定義成員函式 return area; } int Shape ::getGirth(){ return girth; } class Circle : public Shape{ //繼承 private: int redius; public: Circle(){ //新增建構函式避險出現例外的值的錯誤 redius = 0; } void setRedius(int r); }; void Circle :: setRedius(int r){ if ( r >= 0 && r <= 100 ){ redius = r; area = redius * redius * PI ; } } ``` * 透過新增一個專門給子類讀取的成員函數 ```cpp= #define PI 3.14159 class Shape{ private: int area; int girth; protected: void setArea(int a); // 設定一個成員函式可以給子類讀取 void setGirth(int g); public: Shape(){ area = 0; girth = 0; } int getArea(); int getGirth(); }; int Shape ::getArea(){ return area; } int Shape ::getGirth(){ return girth; } void Shape :: setArea(int a){ // 設定該成員函式中的值丟給private area = a; } void Shape :: setGirth(int g){ // 設定該成員函式中的值丟給private girth = g; } class Circle : public Shape{ private: int redius; public: Circle(){ redius = 0; } void setRedius(int r); }; void Circle :: setRedius(int r){ if ( r >= 0 && r <= 100 ){ redius = r; setArea(redius * redius * PI); // 呼叫protected } } ``` > 主要必須記得要讓子類碰的不是成員變數,而是成員函式。這樣的寫法比較正確,確保製作出來的類別符合封裝的原則 --- ## 建構函式 物件建立時,環境會在配置記憶體之後呼叫類別中定義的建構函式。類別開發者會在建構函式中撰寫物件初始化的程式碼,一般是指定資料成員的初值。建構函式的名稱必須與類別名稱一樣,可以有參數列,但不可以有返回型別。參數列可以宣告參數預設值。 > 1. 預設的建構函式 建立物件時,若建立物件的敍述中沒有指定建構函式。環境預設會呼叫沒有參數的建構函式。所以沒有參數的建構函式就是預設的建構函式。 類別中若沒有撰寫建構方法,編譯器會自動產生沒有參數的建構方法。但是,自動產生的建構方法並不會自動指派資料成員的初值,所以建構出來的物件是不安全的。而且,若類別中有撰寫任何建構方法,編譯器就不會自動產生沒有參數的建構方法。 > 2. Overloading 建構函式 類別中除了沒有參數的建構函式,也可以視需求,Overloading 多個建構函式。 > 3. this 寫法: this -> 建構函式中指向的方法 每一個成員函式中都有一個隱含的指標 this。this可以指向呼叫此函式的物件,用來取存物件成員。 主要用途有二: 在專業編輯環境中快速找到要存取的成員 解決成員變數與參數名稱重複的問題。 > 4. 子類別的建構函式指定呼叫父類別的建構函式 若父類別沒有預設的建構函式或 Overloading 多個建構函式,子類別的建構函式可以指定呼叫。 --- ## 多型 - [ :negative_squared_cross_mark:] 持續更新 --- :ghost: 下一章--> **CMake?如何撰寫CMackLists.txt?Makefile?**