---
# System prepended metadata

title: '  程設期末'

---

期末程設

---

Class and Objects

----

關於如果有member variable是以指標形式出現，該如何書寫
```
#include <bits/stdc++.h>
using namespace std;

class Rect{
private:
public://main可以直接改值
    int len;
    int *wid;//調皮
    Rect(int, int*);//參數型態記得改
    void show();
};

Rect::Rect(int len = 0, int *wid = nullptr){//第二個參數先指到空的位置
    this->len = len;
    this->wid = wid;
}

void Rect::show(){
    cout<<"Len : "<<(this->len)<<endl;
    cout<<"Wid : "<<*(this->wid)<<endl;//印出數值記得以"*"取值
}

int main(void){
    Rect sor;//創造物件
    sor.len = 6;//改變物件值
    sor.wid = new int(8);//指標指到無名的整數型態空間
    sor.show();
    return 0;
}
```
 
----

寫出copy construct，以取代default copy constructor
```
#include <bits/stdc++.h>
using namespace std;

class Rect{
private:
public:
    int len;
    int *wid;
    Rect(int, int*);//難度up up
    void show();
    Rect(const Rect&);//參數記得是取參數本身而非複製一份參數（以reference 的方式，也可稱之為共用同一個地址的變數）
};

Rect::Rect(int len = 0, int *wid = nullptr){
    this->len = len;
    this->wid = wid;
}

void Rect::show(){
    cout<<"Len : "<<(this->len)<<endl;
    cout<<"Wid : "<<*(this->wid)<<endl;
}

Rect::Rect(const Rect& sor){
    this->len = sor.len + 2;//本身是啥型態就對應啥型態，最後加上點東西確保真的有用到我寫的copy constructor
    this->wid = new int(*(sor.wid) +2);//因為是指標，指到新另出來的無名同型態空間，並加上點確認有改變的小新機W
}

int main(void){
    Rect sor;//創造第一個
    sor.len = 6;
    sor.wid = new int(8);
    
    Rect sor2 = sor;//啟動copy constructor

    sor.show();
    cout<<endl;
    sor2.show();
    cout<<endl;
    return 0;
}
```

----

使用高級串接技能：Method chaining
```
#include <bits/stdc++.h>
using namespace std;

class Rect{
private:
    int len;
    int wid;
public:
    Rect(int, int);
    Rect& setlen(int);
    Rect& setwid(int);
    void show();
};

void Rect::show(){
    cout<<"Len : "<<(this->len)<<endl<<"Wid : "<<(this->wid)<<endl;
}

Rect::Rect(int len = 0, int wid = 0){
    this->len = len;
    this->wid = wid;
}

Rect& Rect::setlen(int len){
    this->len = len;
    return *this;
}

Rect& Rect::setwid(int wid){//關注回傳值是回傳自己（以變數的形式）
    this->wid = wid;
    return *this;//this為指到自己的指標，指到的值就是自己
}

int main(void){
    Rect sor(1, 2);
    sor.show();

    sor.setlen(6).setwid(8);
    //Method chaining，連續啟動同一個class的member function
    //即自己setlen後再用自己的名義啟動setwid（因為是變數，所以用"."呼叫）
    cout<<endl;
    sor.show();
    
    return 0;
}
```

---

Inheritance（繼承）

<ul>
    <p>四個不可以繼承的東西</p>
    <li>constructor 和 destructor</li>
    <li>Operator overloading 的'='
        <strong>只有等於不可以</strong>
    </li>
</ul>

----

奇妙繼承規則：

|形式|具體|
|---|----|
|public|任何人都可以訪問、存取，包括main（main為外人），故多作為外人查看、修改本身class創造的object中protected與private資料|
|protected|只有自己、繼承的子類別可以訪問，外人不可以訪問、存取|
|private|僅限自己可以訪問、修改，子類別無論以何種形式繼承皆無法訪問修改|

----

個別介紹

----

|隨便沒有限制|以public方式繼承|
|------|------|
|**父類別（原本形式）** |**子類別（繼承後形式）**|
|public|public|
|protected|protected|
|private|**不接受訪問、存取**|

<hr>

練習使用public的繼承
```
#include <bits/stdc++.h>
using namespace std;

class shape{//父類別
public:
    double area;
    void show();
};

void shape::show(){
    cout<<(this->area)<<endl;
}

class circle:public shape{//子類別（circle），以public的方式繼承父類別（shape）
public:
    double radius;
};

int main(void){
    circle object;//創造子類別物件
    
    object.radius = 2.0;//main（外人）使用物件public member variable
    
    object.area = (object.radius * object.radius * acos(-1));
    //外人使用物件父類別public member variable
    //小知識~acos(-1) = 3.14159....
    
    object.show();
    return 0;
}
```

----

|隨便沒有限制|以protected方式繼承|
|------|------|
|**父類別（原本形式）** |**子類別（繼承後形式）**|
|public|**protected**|
|protected|protected|
|private|不接受訪問、存取|

----

|隨便沒有限制|以private方式繼承|
|------|------|
|**父類別（原本形式）** |**子類別（繼承後形式）**|
|public|**private**|
|protected|**private**|
|private|不接受訪問、存取|

----

以public繼承會怎樣：父類的public是我的public，父類的protected是我的protected

以protected繼承會怎樣：父類的public是我的protected，父類的protected是我的protected

以private繼承會怎樣：父類的public是我的private，父類的protected是我的private

**三種形式繼承private皆無權力訪問、修改**

```
#include <bits/stdc++.h>
using namespace std;

class shape{//父類別
public:
    int pub_member;
protected:
    int pro_member;
private:
    int pri_member;
};

class circle: public shape{//子類別以public方式繼承
public://設成public外人（main）才有權利訪問、存取
    void accessPub();//以此形式繼承（public）可以訪問父類別public
    void accessPro();//以此形式繼承（protected）可以訪問父類別protected
    // void accessPri();//以此形式繼承（private）無法訪問、存取
};

void circle::accessPub(){
    pub_member = 5;
    cout<<"OK and pubtected number is "<<pub_member<<endl;
}

void circle::accessPro(){
    pro_member = 6;
    cout<<"OK and protected number is "<<pro_member<<endl;
}

// void circle::accessPri(){//無權訪問父類private
//     pro_member = 7;
//     cout<<"OK and pritected number is "<<pri_member<<endl;
// }

int main(void){
    circle c;
    
    c.accessPub();//外人可使用類別public所有變數、函數
    cout<<endl;
    
    c.accessPro();
    cout<<endl;

    // c.accessPri();
    // cout<<endl;

    return 0;
}
```

---

建構子（constructor）
當有人用此class建構物件，自動呼叫

----

如果父類有建構子，子類繼承後會怎樣
（注意：只是呼叫父類建構子，並不是繼承，建構子不可以繼承）

新玩意：父類建構子protected也可以被呼叫
（一般為外人main建構物件，因為屬於外人，所以建構子多為public）

```
#include <bits/stdc++.h>
using namespace std;

class shape{
protected://有點神奇
    double area;
    shape();
};

shape::shape(){
    cout<<"Shape created"<<endl;
}

class circle: public shape{
public:
    double radius;
    circle();
};

circle::circle(){
    cout<<"Circle created"<<endl;
}

int main(void){
    circle c;
    return 0;
}

//ans:
//Shape created            父類先執行，stack最深
//Circle created           父類執行完，換自己
```

到最底層後慢慢吐出結果，有如遞迴，最深處的會先pop出stack後執行上一層

----

值得注意的小錯誤：如果父類沒有default constructor
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    double area;
    shape(int);//關注重點
};

shape::shape(int area){//沒錯~只有一個參數版的constructor呦
    this->area = area;
    cout<<(this->area)<<" Parent class is ok ~"<<endl;
}

class circle: public shape{
public:
    double redius;
    // circle();
    circle(): shape(5){//代理建構子
        this->redius = 7;
        cout<<(this->redius)<<" Child class is ok ~"<<endl;
    };
};

// circle::circle(){//不可以用~因為會對應到default father constructor，但default被消失了（自己寫constructor後，default即失效）
//     this->redius = 0;
//     cout<<(this->redius)<<" Child class is ok ~"<<endl;
// }

int main(void){
    circle c;
    return 0;
}

//ans：
//5 Parent class is ok ~
//7 Child class is ok ~
```

樣板2
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    double area;
    shape(int);
};

shape::shape(int area){
    this->area = area;
    cout<<(this->area)<<" Parent class is ok ~"<<endl;
}

class circle: public shape{
public:
    static double redius;//試試看static會怎樣
    // circle();
    circle(): shape(this->redius){
        this->redius = 7;
        cout<<(this->redius)<<" Child class is ok ~"<<endl;
    }
};

double circle::redius = 6;//static定義只能在外面呦

// circle::circle(){
//     this->redius = 0;
//     cout<<(this->redius)<<" Child class is ok ~"<<endl;
// }

int main(void){
    circle c;
    return 0;
}

//ans：
//6 Parent class is ok ~
//7 Child class is ok ~

```

---

copy constructor
當兩個相同class創造的object使用=時，該怎麼操作

----

重點：如果父類別有copy constructor就會使用父類，
剩下沒有的部分自己使用default copy constructor （於自己沒有寫copy constructor時）
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x;
    shape(){}
    shape(const shape&);//告訴我創造同類物件時，如果要複製同類物件該如何複製
};

shape::shape(const shape& sor){//確認有動作
    this->x = (sor.x + 2);
}

class circle: public shape{
public:
    int y;
};

int main(void){
    circle c1;
    c1.x = 10;
    c1.y = 20;

    // circle c2 = c1;           //與下相同
    circle c2(c1);               //與上相同
    
    cout<<"c1 = "<<c1.x<<" "<<c1.y<<endl;
    cout<<"c2 = "<<c2.x<<" "<<c2.y<<endl;
    return 0;
}
```

----

如果我自己也定義了copy constructor那會怎樣
：當同類物件在創造時使用'='會執行自己copy constructor，不會跟父類別有關係
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x;
    shape(){}
    shape(const shape&);
};

shape::shape(const shape& sor){
    this->x = (sor.x + 2);
}

class circle: public shape{
public:
    int y;
    circle(){}
    circle (const circle&);
};

circle::circle(const circle& sor){
    this->x = (sor.x + 3);
}

int main(void){
    circle c1;
    c1.x = 10;
    c1.y = 20;

    // circle c2 = c1;
    circle c2(c1);
    
    cout<<"c1 = "<<c1.x<<" "<<c1.y<<endl;
    cout<<"c2 = "<<c2.x<<" "<<c2.y<<endl;
    return 0;
}

```
ans：
![image](https://hackmd.io/_uploads/SJdaagqf0.png)
可知在自己寫了copy constructor後，沒寫到的就是亂給值，除非其變數以static定義值
（原理：static屬於class而非object，以static令出的變數只有一個記憶體空間）

像這樣
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x;
    shape(){}
    shape(const shape&);
};

shape::shape(const shape& sor){
    this->x = (sor.x + 2);
}

class circle: public shape{
public:
    static int y;
    circle(){}
    circle (const circle&);
};

int circle::y = 200;

circle::circle(const circle& sor){
    this->x = (sor.x + 3);
}

int main(void){
    circle c1;
    c1.x = 10;
    c1.y = 20;     //覆蓋掉200

    // circle c2 = c1;
    circle c2(c1);
    
    cout<<"c1 = "<<c1.x<<" "<<c1.y<<endl;
    cout<<"c2 = "<<c2.x<<" "<<c2.y<<endl;
    return 0;
}

//ans：
//c1 = 10 20
//c2 = 13 20
```


模板2
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x;
    shape(){}
    shape(const shape&);
};

shape::shape(const shape& sor){
    this->x = (sor.x + 2);
}

class circle: public shape{
public:
    int y;
    circle(){}
    circle (const circle&);
};

circle::circle(const circle& sor){
    this->x = (sor.x + 3);
    this->y = (sor.y + 3);
}

int main(void){
    circle c1;
    c1.x = 10;
    c1.y = 20;

    // circle c2 = c1;
    circle c2(c1);
    
    cout<<"c1 = "<<c1.x<<" "<<c1.y<<endl;
    cout<<"c2 = "<<c2.x<<" "<<c2.y<<endl;
    return 0;
}

//ans：
//c1 = 10 20
//c2 = 13 23
```

----

遮蔽效應：shadow
如果父類與子類有同名變數怎麼辦
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x;
};

class circle: public shape{
public:
    double x;
    void showx();
};

void circle::showx(){
    cout<<x<<endl;
    cout<<shape::x<<endl;//因為繼承，可以訪問父類同名變數，以此方式說明指定事父類變數而非我自己的
}

int main(void){
    circle c;
    c.x = 8.7;//我自己是double型態
    c.shape::x = 8.7;//父類別是int型態，所以存入值應為8
    c.showx();
    return 0;
}
//ans：
//circle::x = 8.7
//shape::x = 8
```

比較觀念
訪問class中static變數
觀念：（static在runtime就被建立，無關於物件是否創建，地址永遠不變）
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    static int x;//注意我
};
int shape::x = 0;//在外面初始化，這是規定

class circle: public shape{
public:
    double x;
    void showx();
};

void circle::showx(){
    cout<<x<<endl;
    cout<<shape::x<<endl;
}

int main(void){
    circle c;
    c.x = 8.7;
    shape::x = 8.7;//直接訪問class中static變數
    c.showx();
    return 0;
}
```

---

Member function
（此章著重於複寫override的發生）

----

當子類與父類有同名函數，發生覆寫，只有子類會被執行，
可以理解為子類優先級高於父類
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    double area;
    void draw();
};

void shape::draw(){
    cout<<"Drawing a shape"<<endl;
}

class circle: public shape{
public:
    double reaius;
    void draw();
};

void circle::draw(){
    cout<<"Drawing a circle"<<endl;
}

int main(void){
    circle c;
    c.draw();
    c.shape::draw();//指定要選擇從父類繼承的同名函數
    return 0;
}

//ans：
Drawing a circle
Drawing a shape
```

---

Polymorphism（多形）
重點：一定只能以指標實現

|Compile time polymorphism|Runtime polymorphism|
|-------------------------|--------------------|
|Function overloading 函數多載|Virtual function 虛擬函式|
|Operator overloading 運算子多載||

<hr>

<ol>
    <li>
        <strong>Compile time polymorphism</strong>
    </li>
    <ul>
        <li>
            Function overloading：
            參數個數不同 或 相同參數個數但型態不同的<strong>同名函示</strong>
        </li>
        <li>
            Operator overloading：
            以相同運算子賦與更多自訂義的功能
        </li>
    </ul>
    <li>
        <strong>Runtime polymorphism</strong>
    </li>
    <ul>
        <li>
            Virtual function：
            以父類別創造指標，指向子類別同名函式
        </li>
    </ul>
</ol>

----

基礎版：子類與父類有同名函式
觀念：子類override父類同名函式
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x = 3;
    void show();
};
void shape::show(){
    cout<<"Shape x: "<<x<<endl;
}

class circle: public shape{
public:
    int x = 5;
    void show();
};
void circle::show(){
    cout<<"Circle x: "<<x<<endl;
}

int main(void){
    circle *c = new circle();//多行必用指標
    c->show();//呼叫同名函式，此時子類override父類同名函
    shape* s = new shape();
    s->show();//父類自己呼叫自己有的函示
    return 0;
}

//ans：
//Circle x: 5
//Shape x: 3
```

----

進階觀念：以父類指標指向子類物件
重點：**只有父類可以指向子類，子類不可以指向父類**
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    int x = 3;
    void show();
};
void shape::show(){
    cout<<"Shape x: "<<x<<endl;
}

class circle: public shape{
public:
    int x = 5;
    void show();
};
void circle::show(){
    cout<<"Circle x: "<<x<<endl;
}

int main(void){
    shape* s = new circle();//父類指向子類
    s->show();//此時指標型態為父類，啟動父類自己函示
    ((circle*)s)->show();//轉型成子類型態，以子類override父類同名函式
    return 0;
}

// ans:
// shape x: 3
// Circle x: 5
```

----

Virtual function
噁心新觀念

----

正確的寫法
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    virtual double area();//我不一樣呦
    //被呼叫後發現為virtual function所以自動對應到相應的子類別同名函式
};

double shape::area(){
    return 0;
}

class circle: public shape{
public:
    double radius;
    double area();
};

double circle::area(){
    return acos(-1)*radius*radius;
}

class squre: public shape{
public:
    double side;
    double area();
};

double squre::area(){
    return side*side;
}

double getArea(shape* s){
    return s->area();//呼叫父類別
}

int main(void){
    circle c;
    c.radius = 5;
    cout << "Area of circle is: " << getArea(&c)<< endl;

    squre s;
    s.side = 6;
    cout<< "Area of square is: " << getArea(&s)<< endl;

    return 0;
}
//ans：
//Area of circle is: 78.5398
//Area of square is: 36
```

模板2 （比較學習
為何錯誤？
```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    double area();//我不一樣呦
    //被呼叫後發現非virtual function，又型態為父類，未經轉型，故啟動自己函示
};

double shape::area(){
    return 0;
}

class circle: public shape{
public:
    double radius;
    double area();
};

double circle::area(){
    return acos(-1)*radius*radius;
}

class squre: public shape{
public:
    double side;
    double area();
};

double squre::area(){
    return side*side;
}

double getArea(shape* s){
    return s->area();//此時呼叫父類別
}

int main(void){
    circle c;
    c.radius = 5;
    cout << "Area of circle is: " << getArea(&c)<< endl;

    squre s;
    s.side = 6;
    cout<< "Area of square is: " << getArea(&s)<< endl;

    return 0;
}
//ans：
//Area of circle is: 0
//Area of square is: 0
```

----

最終解：pure virtural function

>觀念：有著pure virtural function的class無法產生物件
且繼承的子類一定要實作父類別所有的pure virtual function否則也無法產稱物件

```
#include <bits/stdc++.h>
using namespace std;

class shape{
public:
    virtual double area() = 0;    //我不一樣呦
};

class circle: public shape{
public:
    double radius;
    double area();
};

double circle::area(){
    return acos(-1)*radius*radius;
}

class squre: public shape{
public:
    double side;
    double area();
};

double squre::area(){
    return side*side;
}

int main(void){
    shape *target = nullptr;//以父類別產生指標

    target = new circle();//父類別指標指向子類別創造的無名物件
    ((circle* )target)->radius = 5;//父類別不具此member variable，要記得轉型
    cout << "Area of circle is: " << target->area()<< endl;
    //以父類別指標呼叫pure virtual function會對應到子類別同名函式

    delete target;//避免memery leak

    target = new squre();
    ((squre* )target)->side = 6;
    cout<< "Area of square is: " << target->area()<< endl;

    return 0;
}

//ans：
//Area of circle is: 78.5398
//Area of square is: 36
```

---

Operator Overloading
運算子重載
觀念：operator 為一個 function

重點：不可以對基本型態做operator overloading

重點：不可多載的運算子
|長相|功用|
|---|----|
|::|範圍解析|
|.|	成員選取|
|sizeof|問多大|
|.\*|成員指標選取|
|?:|條件|
|#|前置處理器轉換成字串|
|##|前置處理器串連|

----

**絕對不可以<mark>對基本型態做運算子重載</mark>**
以下說明，這是錯誤的code：假設對基本型態（int）做operator overloading會怎樣
**參數中至少一者為自己定義的class創造的object或列舉eumerated類型才行**

```
#include <bits/stdc++.h>
using namespace std;

int operator+(int a, int b){//兩個參數都是基本型態，不可以的操作
    return (a+b+1);
}

int main(void){
    int a {0}, b{3};
    cout << a+b << endl;//a與b兩者皆為基本型態，基本型態運算已定，不可以重載
    return 0;
}
```
![image](https://hackmd.io/_uploads/BJHaKSjGA.png)
說明：因為是a與b啟動operator+，而a與b是基本型態，不可以做
<hr>
相對而言，正確的寫法

```
#include <bits/stdc++.h>
using namespace std;

class module{
private:
    int x;
    int y;
public:
    module(int, int);
    module operator+(const module&)const;
    void print()const;
    module(const module&);
};

module::module(const module& other){
    this->x = other.x;
    this->y = other.y;
}

module::module(int a = 0, int b = 0){
    this->x = a;
    this->y = b;
}

module module::operator+(const module& other)const{
    return module((this->x + other.x), (this->y + other.y));
}//定義兩個object相加，回傳無名物件

void module::print()const{
    cout<<"x = "<<(this->x)<<endl;
    cout<<"y = "<<(this->y)<<endl;
}
int main(void){
    module m1(2, 3);
    module m2(4, 5);
    module m3(6, 7);
    module m4 = m1 + m2 + m3;//兩個物件相加，非基本型態
    //加完使用copy constructor將兩個object連接
    m4.print();
    return 0;
}
```
<h4>以結果而言：</h4>

產生6個物件，兩個無名的物件（用在m1+m2+m3），四個有名字的物件

<h4>小細節：</h4>

因為相加，不會想要改到傳進去的東西，故最好是造一個新的物件等於兩者相加的結果，雖然比較占記憶體，但較為合理

----

小於的比較
```
#include <bits/stdc++.h>
using namespace std;

class rect{
public:
    double len;
    double wid;
    bool operator<(const rect& )const;
};

bool rect::operator<(const rect& sor) const{    //參數const：傳進來的參數是不會被改的
    複習~函示const，表示此函示保證不修改任何東西
    return ((this->len)*(this->wid))<(sor.len*sor.wid);
}

int main(void){
    rect r1;
    r1.len = 3, r1.wid = 3;
    rect r2;
    r2.len = 2, r2.wid = 5;
    if(r1<r2){//operator< is called here
        cout<<"rect1 < rect2"<<endl;
    }
    return 0;
}
```

----

<h4>
    一些奇怪的小知識增長了（懶惰鬼天地）
</h4>

```
#include <bits/stdc++.h>
using namespace std;
using namespace rel_ops;//偷吃步小方法，只要寫<和==就行

class rect{
public:
    double len;
    double wid;
    bool operator<(const rect&)const;
    bool operator==(const rect&)const;
    rect(double, double);
};

rect::rect(double l = 0, double w = 0){
    this->len = l;
    this->wid = w;
}

bool rect::operator<(const rect& other)const{
    return ((this->len)*(this->wid)) < ((other.len)*(other.wid));
}

bool rect::operator==(const rect& other)const{
    return ((this->len)*(this->wid)) == ((other.len)*(other.wid));
}

int main(void){
    rect r1(3, 4);
    rect r2(2, 4);
    if(r1 != r2) cout<<"We are not equal"<<endl;      //沒寫但可以運作
    if(r1 > r2) cout<<"r1 is greater than r2"<<endl;  //沒寫但可以運作
    return 0;
}
```

----

"非"怎麼書寫
```
#include <bits/stdc++.h>
using namespace std;

class cmp{
private:
    int inner;
public:
    cmp(int);
    bool operator!()const;
    void print()const;
};

cmp::cmp(int x = 0){
    this->inner = x;
}

bool cmp::operator!()const{     //如何描述反向
    if(inner > 0) return false; // true to false
    else return true;           // false to true
}

void cmp::print()const{
    if(!(*this)) cout<<"false to true"<<endl;  //針對物件反向，體現operator overloading
    else cout<<"true to false"<<endl;
}

int main(void){
    int num {0}; cin>>num;
    cmp tar(num);
    tar.print();
    return 0;
}
```

----

<h4>物件怎麼用陣列寫法</h4>

```
#include <bits/stdc++.h>
using namespace std;

class to_slice{
private:
    int num;
    vector<char> sor;
public:
    to_slice(int num);
    void cauculate();
    void print()const;
    char operator[](int)const;
};

to_slice::to_slice(int num = 0){
    this->num = num;
}

void to_slice::cauculate(){
    string target = to_string(this->num);
    for(int i = 0; i<target.size(); i++){
        sor.push_back(target[i]);
    }
}

char to_slice::operator[](int index)const{//第幾個index是甚麼內容
    assert((index >= 0) && (index < sor.size()));//阻擋取用
    return sor[index];//用原本就定義好的[]回傳
}

void to_slice::print()const{
    for(int i = 0; i<sor.size(); i++){
        cout<<(*this)[i]<<" ";//體現用物件的[]來取用，而不是用內建的[]~operator overloading
    }
    cout<<endl;
}

int main(void){
    int num{0}; 
    cin>>num;
    to_slice now(num);
    now.cauculate();
    now.print();
    int index{0}; 
    cin>>index;
    cout<<now[index]<<endl;//實現operator overloading
    return 0;
}
```

----

<h2>Method Chaining觀念運用</h2>
<h4>搞清楚operator=回傳有沒有reference的差別<br><br>
已每個地址確認過，GUN compiler就是如此</h4>

```
#include <bits/stdc++.h>
using namespace std;

class fun{
private:
    int num;
public:
    // fun operator=(const fun&);
    fun& operator=(const fun&); //回傳值有&
    fun(int num);
    void print()const;
};

fun::fun(int num = 0){
    this->num = num;
}

// fun fun::operator=(const fun& other){
//     this->num = other.num;
//     return *this; //回傳一個與自己相同的物件
// }

fun& fun::operator=(const fun& other){//回傳值有&
    this->num = other.num;
    return *this; //回傳一個與自己相同的物件
}

void fun::print()const{
    cout<<"num = "<<(this->num)<<endl;
}

int main(void){
    fun f1(10);
    f1.print(); //印出f1

    fun f2(20);
    f2.print(); //印出更改前的f2

    fun f3(30);
    f3.print();
    
    cout<<endl<<"f1 = f2 = f3"<<endl;
    f3 = f2 = f1;    //將f1的數值複製到f2
                     //如果operator=回傳值沒有&，即 f2 = f1 是做出與f1內容相同的新無名物件，再與f3做一次operator=，因為新物間內容與f1相同，所以將內容複製給f3也沒問題，只是又做了內容相同的新無名物件
                     //如果operator=回傳值有&，即 f2 = f1 回傳的是f2，因為f2值與f1相同，再與f3做operator=，f3就會與f2值相同，最後回傳f3
    cout<<"f1 : ";
    f1.print();
    cout<<"f2 : ";
    f2.print();
    cout<<"f3 : ";
    f3.print();
    return 0;
}
```

----

<h3>再再一次的Method Chaining觀念強調</h3>

<h4>如果沒有使用&會怎樣呢？</h4>

```
#include <bits/stdc++.h>
using namespace std;

class fun{
private:
    int len;
    int wid;
public:
    fun(int, int);
    fun setlen(int);
    fun setwid(int);
    void print();
};

void fun::print(){
    cout<<"Length: "<<(this->len)<<" and Width: "<<(this->wid)<<endl;
}

fun::fun(int len = 0, int wid = 0){
    this->len = len;
    this->wid = wid;
}

fun fun::setlen(int len){
    this->len = len;
    return *this;
}

fun fun::setwid(int wid){
    this->wid = wid;
    return *this;
}

int main(void){
    fun obj(5, 10);
    cout<<"Before : ";                   // Before : Length: 5 and Width: 10
    obj.print();                         //確認constructor有好好工作
    
    cout<<"After : ";
    obj.setlen(15).setwid(20).print();   // After : Length: 15 and Width: 20
                                         //雖印出結果正確，但因為setlen與setwid都不是回傳自己記憶體的參照（共用同一個記憶體空間的不同名變數），
                                         //以obj啟動setlen，正確改道obj物件的len，但回傳內容相同的無名物件，
                                         //其啟動setwid，再回傳與此無名物件內容相同的另一無名物件（len：15 wid：20），
                                         //最後以此無名物件啟動print，不回傳任何東西
    cout<<"Object inner ";
    obj.print();                         // Object inner Length: 15 and Width: 10
                                         //清楚呈現出obj只有len被改到
    
    return 0;
}
```

<hr>
<h4>那~如果有&又會怎樣呢</h4>

```
#include <bits/stdc++.h>
using namespace std;

class fun{
private:
    int len;
    int wid;
public:
    fun(int, int);
    fun& setlen(int);    //加上&
    fun& setwid(int);    //加上&
    void print();
};

void fun::print(){
    cout<<"Length: "<<(this->len)<<" and Width: "<<(this->wid)<<endl;
}

fun::fun(int len = 0, int wid = 0){
    this->len = len;
    this->wid = wid;
}

fun& fun::setlen(int len){    //回傳與自己記憶體相同的不同名變數
    this->len = len;
    return *this;
}

fun& fun::setwid(int wid){    //回傳與自己記憶體相同的不同名變數
    this->wid = wid;
    return *this;
}

int main(void){
    fun obj(5, 10);
    cout<<"Before : ";
    obj.print();                         //length 5 and width 10
    cout<<"After : ";
    obj.setlen(15).setwid(20).print();   //length 15 and width 20
                                         //以obj啟動setlen，回傳自己（共用記憶體空間的同名變數，就是我自己）
                                         //再用obj自己啟動setwid，回傳自己，
                                         //在再調用自己的print
    cout<<"Object inner ";
    obj.print();                         //length 15 and width 20
                                         //真的真的真的是改到自己呦
    return 0;
}
```

<hr>
<h4>非常不幸~笨笨的你看到這裡還不懂...乖乖用指標，啥都別想了</h4>

```
#include <bits/stdc++.h>
using namespace std;

class fun{
private:
    int len;
    int wid;
public:
    fun(int, int);
    fun* setlen(int);     //回傳指標，這裡指回傳自己的記憶體位置
    fun* setwid(int);     //回傳指標，這裡指回傳自己的記憶體位置
    void print();
};

void fun::print(){
    cout<<"Length: "<<(this->len)<<" and Width: "<<(this->wid)<<endl;
}

fun::fun(int len = 0, int wid = 0){
    this->len = len;
    this->wid = wid;
}

fun* fun::setlen(int len){   //我不一樣呦~
    this->len = len;
    return this;             //回傳指到自己的指標，意思是this指到我自己，this存的值就是自己的記憶體位置
}

fun* fun::setwid(int wid){
    this->wid = wid;
    return this;
}

int main(void){
    fun obj(5, 10);
    cout<<"Before : ";
    obj.print();                           //length 5 and width 10
    cout<<"After : ";
    obj.setlen(15)->setwid(20)->print();   //length 15 and width 20
                                           //以obj物件發動setlen，回傳自己記憶體位置，
                                           //此時是指標型態，指標存的值是自己的記憶體位置，用->調用自己setwid
                                           //此時依然是指標型態，調用自己print
                                           //最後不回傳任何東西結束這回合
    cout<<"Object inner ";
    obj.print();                           //length 15 and width 20
                                           //以物件型態obj調用print，不回傳任何東西
    return 0;
}
```

----

<h2>大統整</h2>

<h3>有無&會怎樣</h3>

|有&|沒有&|
|---|----|
|**回傳自己**<br>回傳與自己共用相同記憶體空間的不同名變數<br>在這裡傳進來的與回傳的都是相同名字|回傳與自己內容相同的**另一個無名物件**<br><mark>存在潛在風險</mark>，希望更改但未更改<br>**小心使用**|
<hr>
<h3>指標與非指標</h3>

>重拾觀念：指標就是變數，只是存的東西是**地址**

|變數型態|指標型態|
|-------|------|
|就直接創<br>int<br>float<br>double<br><mark>自己定的class</mark><br>...|即變數型態加上*|
|以**變數**取值<br>int a = 0;<br>a = 9;|以\*取值<br>int \*a = nullptr;<br>a = new int(9);<br>\*a = 87;|
|以&調取變數地址<br>int a = 3;<br>cout<<&a<<endl;|把自己當變數調取即可取道地址<br>int \*a = nullptr;<br>a = new int(9);<br>cout<<a<<endl;|

<h4>重點：當指標使用&與不使用&（取址的意思）是不同的呦</h4>

|使用&|不使用&|
|----|------|
|取到**指標本身**的地址<br>而非所存變數的地址|即取**所存變數的地址**|
| int \*a = nullptr;<br>a = new int(9);<br>cout<<&a<<endl;<br>&a是指標a的地址<br> |int \*a = nullptr;<br>a = new int(9);<br>cout<<a<<endl;<br>a是令出新空間的地址<br>|
<hr>

><h3>this是什麼？</h3>
>this是指到自己物件的指標
|存甚麼|調用方式|
|-----|-------|
|存自己地址|與**指標**相同|
<h3>
    所以~&this與this記憶體位置是不同的喔
</h3>

----

<h4>如何轉型物件</h4>

```
#include <bits/stdc++.h>
using namespace std;

class fun{
private:
    double number;
public:
    operator int();
    fun(double);
    fun(const fun&);
    void print();
};

fun::fun(double num = 0){
    this->number = num;
}

fun::fun(const fun& other){
    this->number = other.number;
}

fun::operator int(){
    return static_cast<int>(this->number);
}

void fun::print(){
    cout<<"Number : "<<(this->number)<<endl;
}

int main(void){
    fun f1(3.14);
    f1.print();
    fun f2 = int(f1)+3.14; //對物件進行轉型後為int + int，為基本型別，故不用operator+
                           //最後使用copy constructor複製一個新的物件給f2
    f2.print();

    return 0;
}
```

----

<h3>Function object（Functor）</h3>

>觀念：將class所創的物件如同function般呼叫
>即只要寫出名字（物件名）和參數（如同function用'()'包在一起）即可

```
#include <bits/stdc++.h>
using namespace std;

class roundArea{
public:
    double operator()(double, double);  //overloading () operator，使得类可以像函数一样被调用
    roundArea(){}                       //default constructor
    void calculate(double, double);
};

double roundArea::operator()(double r1, double r2){  //重點：因為overloading過()所以可以以物件呼叫
    return (acos(-1)*r1*r2);
}

void roundArea::calculate(double r1, double r2){
    double area = (*this)(r1, r2);     //物件调用() operator，實現function object的理念，把类看成function
    cout<<area<<endl;
}

int main(void){
    roundArea ans;         //以default constructor初始化ans
    ans.calculate(3, 4);   //调用calculate函数
    return 0;
}
```

---

<h3>
    Template 模板
</h3>

----

<p>
    <mark><strong>超級重要的細節</strong></mark>關於default value這回事
</p>

><h2>以下開始</h2>

<hr>

<p>最一般的，證明<mark>default value寫在定義就可以了</mark></p>
    
```
int add(int a = 0, int b = 0);  //default value 寫在定義

int main(void){
    cout<<add()<<endl;
}

int add(int a, int b){
    return (a+b);
}

ans: 0
```
<hr>
<p>進階~換成<mark>class</mark></p>

```
class myclass{
private:
    int num;
public:
    myclass(int num = 0);        //default value寫在定義
    int add(int input = 0);      //default value寫在定義
};

myclass::myclass(int num){       //不須重複default value
    this->num = num;
}

int myclass::add(int input){
    return ((this->num) + input);
}

int main(void){
    myclass sor;                //使用default value的建構子
    cout<<sor.add()<<endl;
    return 0;
}

ans: 0
```

<hr>

<p>
    <i>function template</i>再提升一下
</p>

```
template<typename T>
T add(T a = 0, T b = 0);            //於定義宣告default value

int main(void){
    int a{4}, b{6};
    cout<<add<int>()<<endl;         //使用default value的function template
    cout<<add<int>(a, b)<<endl;
    return 0;
}

template<typename T>
T add(T a, T b){                    //描述函示，不需要再寫default value
    return (a + b);
}

ans: 0
     10
```
<hr>
<h4>
    真的真的真的最後了
</h4>
<h2>
    <i>class template</i>
</h2>

```
#include <bits/stdc++.h>
using namespace std;

template<class T>
class myclass{
private:
    T num;
public:
    myclass(T num = 0);            //默認參數需要放在類別定義裡面
    T add(T input = 0);
};

template<class T>
myclass<T>::myclass(T num){
    this->num = num;
}

template<class T>
T myclass<T>::add(T input){
    return ((this->num) + input);
}

int main(void){
    myclass<int> sor;           //使用defalut value建構子
    cout<<sor.add()<<endl;      //使用default value 的 add函示

    myclass<double> sor2(1.2);  //替換default value，用同一個建構子建構
    cout<<sor2.add(2.3)<<endl;  //替換default value，用add函示加上2.3

    return 0;
}

```
<hr>
<h1>
    恭喜~~結束惹W
</h1>

<p>
    總結
</p>

|   |一般function|一般class|function template|class template|
|---|------------|--------|-----------------|--------------|
|default value<br>使用方式|1.於定義宣告<br>2.定義只宣告型態，待實際實現函示功能再給默認值|與一般function一樣，有兩種方式|<strong>只能在定義給默認值</strong>|<strong>只能在定義給默認值</strong>|

>統整：不要手賤將default value寫在實現function、member function的地方，要寫default value 一律在定義就寫好

----

<p>勤奮小學生手賤一波：Ｐ</p>

><i>question：</i>如果寫了function template，又不在定義寫default value，寫在實現函示的地方，會過嗎~？

```
template<typename T>
T add(T, T);                      //這裡不給default value就不要用default value

int main(void){
    int a{4}, b{6};
    cout<<add<int>()<<endl;         
    cout<<add<int>(a, b)<<endl;
    return 0;
}

template<typename T>
T add(T a = 0, T b = 0){           //不准這樣做         
    return (a + b);
}

```
><i>Answer：</i>就是不可以...你TM能不能乖一點，compiler就是看不懂你在幹啥

![image](https://hackmd.io/_uploads/r1-AmTNm0.png)

<h1>再再宣導：default value一律寫在定義</h1>

----

<h3>課堂PPT開始~</h3>
<hr>
<p>複習以前學過的Template（funtion template）</p>

```
#include <bits/stdc++.h>
using namespace std;

template<class T>
int mymin(T data[], int size){                 //接受任意型態陣列，並傳入自己大小
    int index {0};                             //最小值的索引   
    for(int i = 0; i<size; i++){
        if(data[i]<data[index]){
            index = i;
        }
    }
    return index;
}

int main(void){
    int sor1[]{68, 27, 32};
    double sor2[]{1.2, 3.4, 5.6, 7.8, 9.0};
    cout<<mymin<int>(sor1, 3)<<endl;           //指定模板未定義型態T為int型態
                                               //寫法：呼叫名字，寫出定義型態T，寫出函示需要參數
    cout<<mymin<double>(sor2, 5)<<endl;        //指定模板未定義型態T為double型態
    return 0;
}
```

----

<p>
    以前的<strong>變形</strong>
</p>
<p>
    <mark>知道參數可以不用限定typename及class</mark>
</p>

```
#include <bits/stdc++.h>
using namespace std;

template<class T, int num = 78> //給定template default value，注意num屬於template而非class
class fun{
public:
    fun(int count = 22);        //給定class template的constructor default value
    int count;
    void print();
};

template<class T, int num>
fun<T, num>::fun(int count){
    this->count = count;
}

template<class T, int num>
void fun<T, num>::print(){
    cout<<"Count: "<<count<<endl;
    cout<<"num: "<<num<<endl;           //class template中可以使用template的參數num與T
}

int main(void){
    fun<int> sor;               //使用class template 中帶有default value的constructor
    sor.print();                //使用class template的member function

    // cout<<sor.num<<endl;     //問出以下問題
    
    return 0;
}

ans:22
    78

```
<hr>
<p>既然class template可以使用template中的參數，那外人可不可以透過class訪問template參數</p>

```
#include <bits/stdc++.h>
using namespace std;

template<class T, int num = 78> //給定template default value，注意num屬於template而非class
class fun{
public:
    fun(int count = 22);        //給定class template的constructor default value
    int count;
    void print();
};

template<class T, int num>
fun<T, num>::fun(int count){
    this->count = count;
}

template<class T, int num>
void fun<T, num>::print(){
    cout<<"Count: "<<count<<endl;
    cout<<"num: "<<num<<endl;           //class template中可以使用template的參數num與T
}

int main(void){
    fun<int> sor;               //使用class template 中帶有default value的constructor

    cout<<sor.num<<endl;         //報錯!!!!!!!!!!!!!!!!!!!!!!!!
    return 0;
}
```
><h2><mark>就是不可以</mark>，非class中的member variable</h2>
![image](https://hackmd.io/_uploads/SJSVo6N7R.png)

----

>在class template<strong>不能做</strong>的事：將cin / cout寫在一行內

```
#include <bits/stdc++.h>
using namespace std;

template<class T, int size = 2>
class Stack{
private:
    int count;
    T buffer[size];
public:
    Stack(int count = 0);
    int push(T);
    T pop();
    void print();
};

template<class T, int size>
void Stack<T, size>::print(){
    cout<<"Stack: ";
    for(int i = 0; i<count; i++){
        cout<<buffer[i]<<" ";
    }
    cout<<endl<<"Count: "<<(this->count)<<endl;
}

template<class T, int size>
Stack<T, size>::Stack(int count){
    this->count = count;
}

template<class T, int size>
int Stack<T, size>::push(T value){
    if((count-1) > size) return -1;
    else buffer[count++] = value;
    return count;
}

template<class T, int size>
T Stack<T, size>::pop(){
    if(count == 0) throw "Stack is empty";  //已經沒有東西了，拋出錯誤
    return buffer[--count];
}

int main(void){
    Stack<int> sor;

    //測試第一部分輸出，此輸出符合需求
    cout<<"First index :"<<sor.push(4)<<endl;
    cout<<"Second index:"<<sor.push(5)<<endl;
    cout<<"Third index :"<<sor.push(6)<<endl;
    cout<<endl;

    //測試第二部分輸出，此輸出不符合需求，會於期望的輸出呈現完全相反
    // cout<<sor.push(4)<<endl<<sor.push(5)<<endl<<sor.push(6)<<endl;
    // cout<<endl;

    sor.print();
    cout<<endl;

    while(1){
        try{                        //嘗試，即一定會做的事
            auto value = sor.pop();  //因為這裡用class template，回傳無法預期的type故交給compiler判斷
            cout<<value<<endl;
        }
        catch(const char* error){
            cout<<"Error: "<<error<<endl; //接到錯誤拋出，印出接到的東西（丟出字串，故用字串型態接）
            break;
        }
    }

    return 0;
}
```
正確輸出： 
![image](https://hackmd.io/_uploads/S1WVgR47C.png)
<hr>

錯誤輸出：
![image](https://hackmd.io/_uploads/HJQ9zRV70.png)

>可以看出整個放進去的方式就不符合期待，所以<mark>template的cin，cout不要寫在一起</mark>，順序會不符期待

----

<p>class template</p>
<p>將上一個範例陣列型態改成class</p>

```
#include <bits/stdc++.h>
using namespace std;

template<class T, int size = 2>           //給定default size value
class Stack{
private:
    int count;
    T buffer[size];
public:
    Stack(int count = 0);                //給定default value
    int push(T);
    int pop();
    void print();
};

template<class T, int size>
void Stack<T, size>::print(){
    cout<<"Stack: ";
    for(int i = 0; i<count; i++){
        cout<<buffer[i].id<<" ";
    }
    cout<<endl<<"Count: "<<(this->count)<<endl;
}

template<class T, int size>
Stack<T, size>::Stack(int count){
    this->count = count;
}

template<class T, int size>
int Stack<T, size>::push(T value){
    if((count-1) > size) return -1;
    else buffer[count++] = value;
    return count;
}

template<class T, int size>
int Stack<T, size>::pop(){                        //改變回傳值為int，回傳物件中id
    if(count == 0) throw "Stack is empty";
    return (buffer[--count].id);
}

class car{
public:
    int id;
    car(int id = 0);
};

car::car(int id){
    this->id = id;
}

int main(void){
    car c1(4), c2(5), c3(6);
    Stack<car, 2> sor;

    cout<<sor.push(c1)<<endl;
    cout<<sor.push(c2)<<endl;
    cout<<sor.push(c3)<<endl;

    sor.print();
    cout<<endl;

    while(1){
        try{
            auto value = sor.pop();
            cout<<value<<endl;
        }
        catch(const char* error){
            cout<<"Error: "<<error<<endl;
            break;
        }
    }

    return 0;
}
```
符合期待輸出：
![image](https://hackmd.io/_uploads/HyvEuC4XR.png)

----

<h2><i>Template specialization</i> 模板特化</h2>

|  |function template<br> specialization|class template<br> specialization|
|--|-----------------------------|---------------------------------|
|區別|只引許存在<mark>完全特化</mark>|1.完全特化<br>2.部分特化|
|理由|function overloading與完全特化很像，寫法也比較簡單|沒有任何東西叫做class overloading，<br>但做的事情也是修改參數類型<br>（僅限修改參數type，不可以修改參數數量）|
<hr>

<p>一次學習class template 特化</p>

此範例：因為訪問指標與訪問指標內的值是不同的，故需要特別注意（特殊行為）

```
#include <bits/stdc++.h>
using namespace std;

template<class T, class U>         //General template
class compare{
private:
public:
    bool check(T , U);
};

template<class T, class U>
bool compare<T, U>::check(T a, U b){
    if(a == b) return true;
    else return false;
}

template<class T>                 //partial specialization template for int*（部分特化模板）
class compare<T, int*>{           //沿用原class template的 T type，但将 U 类型限定为 int*，實現部分特化
private:
public:
    bool check(T, int*);
};

template<class T>
bool compare<T, int*>::check(T a, int* b){
    if(a == *b) return true;
    else return false;
}

template<>                      //full specialization template for int*（全特化模板）
class compare<int*, int*>{      //將T 类型限定為 int*，且将 U 类型限定為 int*，實現全特化，即參數全部修改
private:
public:
    bool check(int*, int*);
};

bool compare<int*, int*>::check(int* a, int* b){
    if(*a == *b) return true;
    else return false;
}

int main(void){
    cout<<boolalpha;

    int i1{6}, i2{8}, i3{8};
    int *p1{&i1}, *p2{&i2}, *p3{&i3};
    
    compare<int, int> c1;                 //general template
    cout<<c1.check(i1, i2)<<endl;
    cout<<c1.check(i2, i3)<<endl;

    compare<int, int*> c2;                //partial specialization template 
    cout<<c2.check(i1, p2)<<endl;
    cout<<c2.check(i2, p3)<<endl;

    compare<int*, int*> c3;                //full specialization template 
    cout<<c3.check(p1, p2)<<endl;
    cout<<c3.check(p2, p3)<<endl;
    return 0;
}
```
<P>答案</P>

![image](https://hackmd.io/_uploads/SkKEUyS70.png)
>為何寫到指標就需要特化？
<h3>GPT是你的好夥伴</h3>

特化一个类型的主要需求和场景包括性能优化、处理特定类型的特殊行为、处理不支持的类型、编译时元编程以及提供泛化接口的不同实现。通过使用模板特化，可以为特定类型提供定制的实现，从而提高代码的灵活性、性能和可维护性。

<P>function template</P>
<strong>沒有部分特化，只有重載</strong>

```
#include <bits/stdc++.h>
using namespace std;

template<typename T, typename P>           //generic template function宣告
void print(T, P);

template<typename T, typename P>           //實現function template （一般的形式）
void print(T t, P p){
    cout << t << " " << p << endl;
}

template<typename T>                        //以重載方式實現function template （名字前不必加'<>'，因為這行為非部分特化，是重載）
void print(T t, double *p, char c){
    cout<<t<<" "<<*p<<" "<<c<<endl;
}

template<>                                  //specialization for int* and double*（完全特化）
void print<int*, double*>(int *t, double *p){
    cout<<*t<<" "<<*p<<endl;
}

int main(void){
    int a{10}; double b{2.3}; char ch{'a'};
    int *pa = &a; double *pb = &b;

    print<int, double>(a, b);                             //function template，最一般的函示模板
    print(a, pb, ch);                                     //實現function overloading，修改變數type，增加變數數目
    print<int*, double*>(pa, pb);                         //實現function specialization，完全特化

    return 0;
}   
```
<hr>

<p>相較而言，如果不使用完全特化，也是可以全部使用重載</p>

```
#include <bits/stdc++.h>
using namespace std;

template<typename T, typename P>           //generic template function宣告
void print(T, P);

template<typename T, typename P>           //實現function template （一般的形式）
void print(T t, P p){
    cout << t << " " << p << endl;
}

template<typename T>                        //以重載方式實現function template （名字前不必加'<>'，因為這行為非部分特化，是重載）
void print(T t, double *p, char c){
    cout<<t<<" "<<*p<<" "<<c<<endl;
}
                                                
void print(int *t, double *p){              //實現function overloading，修改變數type                     //其實也跟完全特化長得差不多
    cout<<*t<<" "<<*p<<endl;
}

int main(void){
    int a{10}; double b{2.3}; char ch{'a'};
    int *pa = &a; double *pb = &b;

    print(a, b);                             //function template，最一般的函示
    print(a, pb, ch);                        //實現function overloading，修改變數type，增加變數數目
    print(pa, pb);                           //實現重載

    return 0;
}   
```

----

<h2>
    額外小知識~請問assert與static_assert有什麼差別
</h2>

><strong>Answer</strong>：assert再runtime時如果有錯誤才會停下<br>但是static_assert在compile time如果有錯就會報錯，<br>且錯誤訊息可以自己寫，較具可讀性。

<p>以下提供小小範例</p>

```
#include <bits/stdc++.h>
using namespace std;

template<class T>
class Equal{
private:
public:
    static_assert(!is_pointer<T>(), "Pointer type is not allowed.");    //知道指標地址不能比較，直接擋下來
                                                                        //不是指標才可以繼續往下做
    bool check(T data1, T data2){
        if(data1 == data2){
            return true;
        }
        else{
            return false;
        }
    }
};

int main(void){
    int i1 = 6, i2 = 8, i3 = 8;
    Equal<int> e1;
    cout<<boolalpha<<e1.check(i1, i2)<<endl;         // false
    cout<<boolalpha<<e1.check(i3, i2)<<endl;         // true
    Equal<double> e2;
    cout<<boolalpha<<e2.check(5.0, 3.0)<<endl;       // false
    cout<<boolalpha<<e2.check(5.0, 5.0)<<endl;       // true
    
    Equal<int*> e3;                             // Pointer type is not allowed. This will cause a compile-time error.
    cout<<boolalpha<<e3.check(&i1, &i2)<<endl;
    cout<<boolalpha<<e3.check(&i2, &i3)<<endl;
    return 0;
}
```
>當然~此題可以使用function overloading與function template完全特化處理掉

----

<p><i>algorithm</i>函示庫中其中兩個小小功能</p>

>比較陣列中的最小、最大項

```
#include <bits/stdc++.h>
using namespace std;

int main(void){
    int sor[]{30, 27, 19, 56, 72, 36};
    double sor2[]{3.6, 7.2, 8.5, 1.6, 9.1, 5.6};

    cout<<*(min_element(sor, sor+6))<<endl;    //sor中最小者，因為回傳是地址，取值使用'*'
    cout<<*(max_element(sor, sor+6))<<endl;     //sor中最大者
    cout<<*(min_element(sor2, sor2+6))<<endl;
    cout<<*(max_element(sor2, sor2+6))<<endl;
    return 0;
}

ans:19
    72
    1.6
    9.1
```

----

<p>沒東西講~開始套container</p>

<a href="https://cplusplus.com/reference/stack/stack/">Stack in Cplusplus</a>

```
#include <bits/stdc++.h>
using namespace std;

int main(void){
    stack<int> s;
    s.push(4);
    s.push(5);
    s.push(6);
    
    cout<<s.size()<<endl;
    while(!s.empty()){
        cout<<s.top()<<" ";
        s.pop();
    }

    return 0;
}
```

---

<h2>First Class Function</h2>

>當一個function以<strong>參數</strong>的形式傳入另一個function，<br>即稱為<i>First Class Function</i>

----

<h4>Function Pointer 用指標指向函示第一個地址</h4>

```
#include <bits/stdc++.h>
using namespace std;

int sum(int a, int b){
    return a+b;
}

int product(int a, int b){
    return a*b;
}

int main(void){
    int (*pfunc)(int, int) = nullptr;    // 用指標指向function，在這裡初始化為nullptr
                                         // 這裡限制只能指向參數為int, int，且迴船值為int的function
                                         
    pfunc = sum;                          // 指標指向sum函數
    cout << pfunc(2, 3) << endl;          // 呼叫sum函數並輸出結果5

    pfunc = product;                      // 指標指向product函數
    cout << pfunc(2, 3) << endl;          // 呼叫product函數並輸出結果6
    return 0;
}
```

----

<h4>學會Function Pointer，就可以<mark>讓function變成參數</mark>實現高階函示</h4>

```
#include <bits/stdc++.h>
using namespace std;

void onokclick(){                         //callback function，因為其他function而被動觸發
    cout<<"OK"<<endl;
}

void oncancelclick(){                      //callback function，因為其他function而被動觸發
    cout<<"Cancel"<<endl;
}

void setonclick(void (*pfunc)() = nullptr){          //設定onclick function，預設為nullptr
    if(pfunc == nullptr) throw "No function to call";
    pfunc();
}

int main(void){
    try{
        setonclick();           //直接使用nullptr function，會出現未定義行為，使程式崩塌，因此在此加上try-catch
    }
    catch(const char* msg){
        cout<<msg<<endl;
    }
    setonclick(onokclick);       //使用onokclick function
    setonclick(oncancelclick);   //使用oncancelclick function
    return 0;
}
```
<hr>
><p>或return</p>

```
#include <bits/stdc++.h>
using namespace std;

void onokclick(){                         //callback function，因為其他function而被動觸發
    cout<<"OK"<<endl;
}

void oncancelclick(){                      //callback function，因為其他function而被動觸發
    cout<<"Cancel"<<endl;
}

void setonclick(void (*pfunc)() = nullptr){          //設定onclick function，預設為nullptr
    if(pfunc == nullptr){
        cout<< "No function to call"<<endl;
        return;
    }
    pfunc();
}

int main(void){
    setonclick();                //設定onclick function為nullptr
    setonclick(onokclick);       //使用onokclick function
    setonclick(oncancelclick);   //使用oncancelclick function
    return 0;
}
```
>callback function：類似一個按鈕，按了後會觸發啥（哪一個function）
>可視為~function是被動觸發，因為調用A function，被包含在其中的B function被觸發了 

---

<h2>
    First Class Function
</h2>

<ul>
    <li>
        <p>
            Callback Function：不由自己呼叫，通常由OS呼叫（EX:按鈕）
        </p>
    </li>
    <li>
        <p>
            Higher Order Function：當一個function將另一個function當變數引入的函示
        </p>
    </li>
    <li>
        <p>
            Lambda：當只需要使用一次，不需要特別給予名字的函示
        </p>
    </li>
</ul>

----

<h4>
    使用std::function方式寫出call back function與higher order function    
</h4>

```
#include <bits/stdc++.h>
using namespace std;

int sum(int, int);                                                          //call back function
int cal(int a, int b, function<int(int, int)>);                             //Higher order function

int main(void){
    int a = 10, b = 20;
    int result = cal(a, b, sum);
    cout << "Sum of " << a << " and " << b << " is " << result << endl;
    return 0;
}

int sum(int a, int b){
    return a + b;
}

int cal(int a, int b, function<int(int, int)>pfunc){                        //使用std::funcion包裝
    return pfunc(a, b);
}
```

----

>不要用std::function來寫class，還是使用古老版本（以下）就好

```
#include <bits/stdc++.h>
using namespace std;

class ex{
protected:
public: 
    int sum(int, int);                                                          //call back function
    // int cal(int a, int b, function<int(int, int)>);                          
    int cal(int a, int b, int(ex::*)(int, int));                                //Higher order function
    ex(){}
};


int main(void){

    ex obj;
    int a = 10, b = 20;
    int result = obj.cal(a, b, obj.sum);
    cout << "Sum of " << a << " and " << b << " is " << result << endl;
    return 0;
}

int ex::sum(int a, int b){
    return a + b;
}

// int ex::cal(int a, int b, function<int(int, int)>pfunc){                        //使用std::funcion包裝
//     return pfunc(a, b);
// }

int ex::cal(int a, int b, int(ex::*pfunc)(int, int)){
    return (this->*pfunc)(a, b);
}
```

---

<h2>
    Lambda Expression書寫方式
</h2>

----

<h4>
    一次看懂Lambda書寫方式    
</h4>

```
#include <bits/stdc++.h>
using namespace std;

int cal(int, int, int(*)(int, int));
int sum(int, int);

int main(void){
    cout<<cal(3, 5, sum)<<endl;                                 //使用higher-order function
    cout<<cal(3, 5, [](int a, int b){return (a+b);})<<endl;      //使用lambda function

    int x = 7, y = 3;
    auto fun0 = [&](){return x+y;};                               //使用lambda function，當使用到外面參數，選擇[=]或[&]
    cout<<fun0()<<endl;                                           //使用lambda function [&]，第一次copy即取xy的變數'地址'  

    auto fun1 = [=](){return x+y;};                               //使用lambda function，當使用到外面參數，選擇[=]或[&]
    x = 10, y = 5;                                                //修改xy的值，但fun1仍使用第一次copy的xy值
    cout<<fun1()<<endl;                                           //使用lambda function [=]，第一次copy即取xy的變數'值'
    cout<<fun0()<<endl;                                           //使用lambda function [&]，第一次copy即取xy的變數'地址'
    return 0;
}

int cal(int a, int b, int(*pfunc)(int, int)){
    return pfunc(a, b);
}

int sum(int a, int b){
    return (a+b);
}
```

----

<h4>
    統整Lambda
</h4>

<table>
    <tr>
        <td>
        </td>
        <td>
            =
        </td>
        <td>
            &
        </td>
    </tr>
    <tr>
        <td>
            差別
        </td>
        <td>
            第一次執行時copy內在需要引入外面變數的<strong>值</strong><br>故以後即使修改外面變數，<br>依然使用第一次copy到的值
        </td>
        <td>
            第一次執行時copy內在需要引入外面變數的<strong>地址</strong><br>故即使以後修改了，由外在引入的變數也會跟著修改
        </td>    
    </tr>
</table>

----