Struct & Class

1111111 大社課

講師:溫室蔡

什麼是 Struct

把一堆變數包在一起

變成一個新型別!

// 寫在 main 外面
struct 名稱 {
    變數一;
    變數二;
    變數三;
}; // <-- 這邊要分號

Struct 範例

然後咧,怎麼用?

struct Person {
    string name;
    double height;
    double weight;
    double bmi;
};

使用 Struct

還可以更方便嗎?

int main() {
    Person p;
    p.name = "Justin";
    p.height = 160.0;
    p.weight = 55.0;
    p.bmi = p.weight / ((p.height/100.0) * (p.height/100.0))
    cout << p.name << '\n'; // Justin
    cout << p.bmi << '\n'   // 21.4844
    return 0;
}

建構式

struct Person {
    string name;
    double height;
    double weight;
    double bmi;
    // 與 struct 同名的 function
    // 不寫回傳型別
    Person(string name_, double height_, double weight_) {
        name = name_;
        height = height_;
        weight = weight_;
        bmi = weight / ((height/100)*(height/100));
    }
};

int main() {
    Person p("Justin", 160, 55);
    cout << p.name << '\n'; // Justin
    cout << p.bmi << '\n';  // 21.4844
    return 0;
}

Struct 裡的函式

struct Person {
    string name;
    // ...
    void say(string content) {
        cout << name << " says " << content;
    }
};

int main() {
    Person p("Justin", 160, 55);
    p.say("hello!"); // Justin says hello!
    return 0;
}

Struct 裡也可以寫函式

稱之為「方法」

Struct 的問題

p.weight 本該與 p.bmi 連動

Person p("Justin", 160, 55);
cout << p.bmi << '\n' // 21.4844
p.weight = 60.0;
cout << p.bmi << '\n' // 21.4844

但只改 p.weight

p.bmi 當然不會跟著改

說說物件導向

物件導向程式設計

(Object-oriented programming)

就是把程式裡的東西都當作「物件」來處理

而「物件」就是套用現實生活中的概念

人是一個物件,有名字、身高、體重

車是一個物件,有品牌、顏色、速度

任何東西都可以是物件

C++ 的 Class

struct 是 C 語言就有的東西

算是物件導向的雛型

C++ 則有了 class,實現完整的物件導向

也就是封裝、繼承、多型

其餘語法跟 struct 差不多

用 Class 重寫 Person

class Person {
public:
    string name;
    double height;
    double weight;
    double bmi;
    Person(string name, double height, double weight);
    void say(string content);
};

欸,方法內容咧

Class 的方法通常實作在外面

Person::Person(string name, double height, double weight) {
    this->name = name;
    this->height = height;
    this->weight = weight;
    this->bmi = weight / ((height/100)*(height/100));
}

void Person::say(string content) {
    cout << this->name << " says " << content << '\n';
}

int main() {
    Person p("Justin", 160, 55);
    p.say("hello!"); // Justin says hello!
    return 0;
}

那個 public 是啥

這就是 class 與 struct 不一樣的地

class 引入了「權限」的概念

public:成員可以被隨意存取

private:成員只能在內部被存取

protected:跟 private 相同

但繼承的 class 也可以存取

Private 成員範例

class Person {
private:
    string name;
    double height;
    double weight;
    double bmi;
public:
    Person(string name, double height, double weight);
    void say(string content);
};

// 其餘方法不變

int main() {
    Person p("Justin", 160, 55);
    cout << p.name << '\n'; // 編譯錯誤
    return 0;
}

Getter & Setter

class Person {
private:
    // ...
public:
    // ...
    // Getter
    string get_name() { return this->name; }
    double get_height() { return this->height; }
    double get_weight() { return this->weight; }
    double get_bmi() { return this->bmi; }
    // Setter
    void set_weight(double new_weight);
};

// ...

int main() {
    Person p("Justin", 160, 55);
    cout << p.get_name() << '\n'; // Justin
    return 0;
}

收伏筆:解決 struct 的問題

void Person::set_weight(double new_weight) {
    this->weight = new_weight;
    this->bmi = new_weight / ((this->height/100)*(this->height/100));
}

int main() {
    Person p("Justin", 160, 55);
    cout << p.get_weight() << '\n'; // 55
    cout << p.get_bmi() << '\n';    // 21.4844
    p.set_weight(60);               // 用 setter 去改 weight
    cout << p.get_bmi() << '\n';    // 23.4375
    return 0;
}

封裝:隱藏物件的細節

剛才的就是封裝的實例

使用物件的人不需要知道

內部的變數、計算是如何運作的

他只要使用我寫好的介面(方法)

能達成想做到的事就行了

這也是物件導向的核心概念

下課

你或許有注意到

我沒有講繼承跟多型

那是因為這對基礎語法來說太進階了

且我不能把小社課的內容講走

欲知詳細,請來週三的專案建置小社!