---
# System prepended metadata

title: C/C++程式設計 指標？物件導向？
tags: [programming language]

---

![](https://hackmd.io/_uploads/rkx6gvyAn.png)
# 什麼是C/C++?
* 跨平台語言
* Bjarne Stroustrup 開發
* 系統資源和內存高度控制
* 可移植性,應用在多個平台
* 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++基礎語法
**針對基礎輸出輸入**
```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 =100; //管理空間裡的值
    cout << r << endl; //得到ｒ的位址
    cout << *r << endl; //得到該位址中的值

    return 0;
```
* 另一個指標 的用法
```cpp=
int * r;
    r = new int; //另外派一個空間給ｒ
    * r =100; //管理空間裡的值
    cout << r << endl; //得到ｒ的位址
    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; //得到ｒ的位址
    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？**

























