類別的建構(Constructor)和解構(Destrcutor)是讓設計者定義當類別被宣告或釋放時,自動執行對應的操作處理。通常建構式是用來初始化類別中的屬性,或是調用相關初始化的方法,例如GUI的布局等等,而解構式則是釋放已不再使用的記憶體空間。
建構式語法類似於函式語法,可以多載,且必須與類別名稱相同,但不須標明回傳類型,我們先來看看下面範例:
class Parent {
public:
Parent() { //定義第一種建構式,無須任何輸入參數
m_attr = 0;
std::cout << "Parent has been declared." << std::endl;
}
Parent(int a) { //定義第二種建構式,需給予一個整數型態參數
m_attr = a; //將參數配置於 m_attr 成員變數
std::cout << "Parent has been declared and set the attribute: " << a << std::endl;
}
private:
int m_attr;
};
void main () {
Parent p; //以第一種建構式宣告類別
Parent p2(100); //以第二種建構式宣告類別
}
解構式語法與建構式語法唯一差異就在有無 "~" 在式子開頭,如下範例:
class Parent {
public:
Parent() {
m_attr = new int(0); //動態配置屬性
std::cout << "Parent has been declared." << std::endl;
}
~Parent() { //在開頭加上 "~" 即可
delete m_attr; //釋放 m_attr 佔用的記憶體空間
m_attr = nullptr;
std::cout << "Release the attribte's memory." << std::endl;
}
private:
int *m_attr;
};
類別的建構式和解構式是在類別生命週期的開頭和結束時,自動地被調用。但要特別注意的是,當類別是被動態配置時,設計者需要自行用 delete 關鍵字將類別刪除,類別才會自動地去調用解構式,我們可以看看下面的範例:
class Parent {
public:
Parent() {
m_attr = new int(0); //動態配置屬性
std::cout << "Parent has been declared." << std::endl;
}
~Parent() { //在開頭加上 "~" 即可
delete m_attr; //釋放 m_attr 佔用的記憶體空間
m_attr = nullptr;
std::cout << "Release the attribte's memory." << std::endl;
}
private:
int *m_attr;
};
void func() {
Parent p;
}
void main() {
func();
}
上例中,我們在 func 函式中以靜態配置的方式宣告了 Parent 類別,函式的開頭會調用到 Parent 的建構式,並且在函式執行結束時,調用了解構式。然而,當我們在函式中用動態配置的方式宣告類別 Parent,但沒有在函式結束之前做 delete 時,儘管函式執行已經結束,解構式仍然不會被調用,如下:
void func() {
Parent *p = Parent(); //函式只會調用到建構式。
}
void main() {
func();
}
像這種函式執行完畢,但類別佔用的記憶體空間沒被釋放的情況,我們稱之為內存洩漏(Memory Leakage),嚴重的情況可能會導致整個程式崩壞,因此做好記憶體控管是設計者需要非常注意的事情。
Last updated: