Try  HackMD Logo HackMD
tags: 大一程設-下 東華大學 東華大學資管系 基本程式概念 資管經驗分享

class - 更多的基本語法介紹

前言

前面幾篇筆記只是開胃小菜,幫助大家釐清最基本的概念跟寫法,這篇筆記會多放一些範例,以及你們必須要知道的一些程式寫法。

類別的方法定義與實作分開

這個部分的重要性在 CH12 - separate compilation 會完全體現出來,因為會開始教怎麼引用自己寫的檔案進來,而拆分出去的檔案要怎麼撰寫也很重要,這是身為開發者一定要必備的技能。

比方說你有一個 main.cpp 的檔案,而你自己寫好了幾個類別分別放在不同的檔案內,其實你都可以把他們 include 進來,這樣可以降低程式的複雜性,提高效率。

那甚麼是定義與實作分開呢?其實概念很像 function 的定義寫在上面,實作寫在 main 後面的意思。

下面兩個寫法,意義完全等價。

寫法 1

  • 類別內只定義方法與屬性,沒有實作
#include <iostream> using namespace std; class Animal{ public: // 類別內只定義方法與屬性,沒有實作 Animal(); //default constructor Animal(string n, int a); // user-defined constructor // getter string get_name(); int get_age(); // setter void set_name(string n); void set_age(int a); private: string name; int age; }; int main(){ Animal a1; a1.set_name("amy"); a1.set_age(3); cout << a1.get_name() << " " << a1.get_age() << endl; Animal a2("bob", 5); cout << a2.get_name() << " " << a2.get_age() << endl; } Animal::Animal(){ this->name = ""; this->age = 0; } Animal::Animal(string n, int a){ this->name = n; this->age = a; } string Animal::get_name(){ return this->name; } int Animal::get_age(){ return this->age; } void Animal::set_name(string n){ this->name = n; } void Animal::set_age(int a){ this->age = a; }

可以看到我們把類別內定義的方法全部都放到後面實作,增加程式閱讀性,到 CH12 就會教大家怎麼把這些定義跟實作的程式碼分開。

而這邊的 :: 是什麼意思呢?用中文翻譯也是 的意思,所以你目前應該遇到了三個東西都會唸做 ,分別是 .->::,這邊來說明 ::

雙冒號(::)

雙冒號只會出現在實作類別的時候,像上例這樣把定義跟實作分開,下面實作時Animal::Animal(),代表的是 Animal 類別下「」 Animal() 方法,而因為建構子沒有回傳型別,所以不用在前面加東西。

string Animal::get_name() 呢?
這邊表示的是 Animal 類別下「」 get_name() 方法,因為他的回傳型別是 string,所以最前面必須要加上回傳型別,就跟宣告函式一樣,並無差別。

void Animal::set_name(string n)
Animal 類別下「」 set_name() 方法,回傳型態為 void,沒有回傳值,需要傳入一個 string 參數。

寫法 2

寫法 1 跟寫法 2 的意義完全相同。這是我們平常較常寫的方式。

class Animal{ public: //default constructor Animal(){ this->name = ""; this->age = 0; } // user-defined constructor Animal(string n, int a){ this->name = n; this->age = a; } // getter string get_name(){ return this->name; } int get_age(){ return this->age; } // setter void set_name(string n){ this->name = n; } void set_age(int a){ this->age = a; } private: string name; int age; }; // main 相同,省略
  • 所以總結來說,如果你要做檔案拆分,會用寫法 1,但若類別跟 main 都要放在同個檔案,沒有要拆分,就會用寫法 2。
  • 但通常實務運作不可能不用寫法 1,所以一定要會。

不一樣的初始化類別屬性

相信學了建構子之後,大家都知道怎麼初始化類別屬性了,以上面的例子為例。
當今天物件被實體化的時候,會依照相對應的呼叫方式,初始化類別屬性。

而下面這樣的寫法,常見還有另一種方式,寫法 1 與 寫法 2 意義完全等價。

寫法 1 (一開始教的)

這邊省略其他的內容,只拿建構子。 Animal(){ this->name = ""; this->age = 0; } Animal(string n, int a){ this->name = n; this->age = a; }

寫法 2

Animal() : name(""), age(0){ } Animal(string n, int a):name(n), age(a){ }

錯誤寫法

請千萬不要寫下面這樣!! WRONG!!

Animal() : this->name(""), this->age(0){ } Animal(string n, int a):this->name(n), this->age(a){ }

你可能會問,為什麼?不是要代表類別本身的 name 跟 age 嗎,為什麼不用 this?
把類別屬性初始化用這樣的方式寫的時候,他已經預設冒號後就是為類別內的屬性作初始化了,所以不用再用 this。

請注意,要初始化的屬性放在冒號後,以逗號分隔。

當然這麼詭譎的寫法你覺得它的意義就只有這樣嗎?當然不只摟,但目前我們比較碰不到那裡,我把參考資料給你們,有問題歡迎來問我。但起碼上面要會,這超基本。

Reference