Chris Chung
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    ![](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?**

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully