接下來介紹設計類別的核心概念 - 繼承(Inheritance)。繼承的特性讓類別有很好的拓展性和更好的架構分類,通常在設計程式架構時,會先從主題的最基本元件開始搭建,例如我們要做一個公司員工的資料架構時,可以先設計一個基礎類別為 "員工",然後再從這個 "員工" 類別去衍生出 "基層員工"、"部門主管"、"高階主管" 等等的子類別。
因為子類別繼承了 "員工" 類別,它們之間就形成了父類別和子類別的關係。像這樣的設計,"員工" 類別會具有子類別的共通方法和屬性,例如 "員工" 都會有員工編號、薪資,因此不管是 "基層員工"、"部門主管" 和 "高階主管" 類別都會有這樣的基礎屬性,而這些子類別在基於這樣的基礎上,會被各自設計成自己獨有的方法和屬性,你可以再用 "權力" 這樣的思維方向去考慮如何設計這些子類別。
那麼,我們先來看看類別繼承的語法該如何撰寫:
class Parent {
};
class Child : public Parent {
};
我們先定義了一個類別叫 Parent,然後再定義一個類別 Child 去繼承 Parent,語法上只要在定義類別 Child 之後用 "冒號(:)" 加上父類別名稱即可。你可能會有疑問為何在繼承父類別之前,要再加上 public 呢?
這意思是子類別是以公開存取的方式繼承了父類別,這樣我們要調用父類別 public 的方法時,就可以直接透過子類別去調用,我們來看看下面範例:
class Parent {
public:
void print() {
std::cout << "Hello, I'm parent" << std::endl;
}
};
class Child : public Parent {
};
int main () {
Child c;
c.print();
}
如果在繼承 Parent 類別時,把 public 拿掉,你會發現 Child 類別不能直接用 print 去輸出顯示了,並且在編譯時會報錯誤。你必須得用 Child 自身的方法去調用 Parent 的 print(),如下範例:
class Parent {
public:
void print() {
std::cout << "Hello, I'm parent" << std::endl;
}
};
class Child : Parent {
void call_parent_print() {
print();
}
};
int main () {
Child c;
c.call_parent_print();
}
在前述論及繼承中,我們談論的較偏向類別的深度集合(衍生),而多重繼承則是讓繼承擁有廣度集合(衍生)的特性,這意味著子類別可以不只繼承單一個父類別。
回到前例,假設我們想在員工架構上在建立一個基礎,這個類別可以叫 "工程師",然後這個 "工程師" 類別再衍生出 "軟體工程師" 和 "硬體工程師",這樣我們對員工的分類又更進一個層次分類,當我們想建立一個 "軟體工程師部門主管" 的類別時,就可以讓這個類別去繼承 "軟體工程師" 和 "部門主管"。
那麼,我們要如何撰寫讓一個類別繼承多個類別呢? 可以有幾種寫法,如下範例:
class Employee {
public:
void print1() {
std::cout << "Hello, I'm a employee." << std::endl;
}
};
class Engineer {
public:
void print2() {
std::cout << "Hello, I'm a engineer." << std::endl;
}
};
class Child : public Employee, public Engineer {
};
class Employee {
public:
void print1() {
std::cout << "Hello, I'm a employee." << std::endl;
}
};
class Engineer : public Employee {
public:
void print2() {
std::cout << "Hello, I'm a engineer." << std::endl;
}
};
class Child : public Engineer {
};
值得注意的是,父類別彼此之間要避免有一樣名稱的函式,否則編譯時可能會出現錯誤,因為如果子類別有調用該函式,會變得不曉得呼叫的是哪個父類別的函式。
還記得上一篇談論封裝時,我們有提到 protected 修飾詞底下的方法和屬性是只有自身和子類別可以存取的吧? 那麼它在工程意義上是什麼意思呢? 假設我們有一個屬性名叫 "m_salary",我們想讓這個屬性可以在所有的衍生類別中被存取,但又不希望它是公開可以隨意被更改的,這時候就可以用 protected,如下範例:
class Employee {
public:
void print1() {
std::cout << "Hello, I'm a employee." << std::endl;
}
protected:
int m_salary;
};
class Engineer {
public:
void print2() {
std::cout << "Hello, I'm a engineer." << std::endl;
}
};
class Child : public Employee, public Engineer {
public:
void set_salary(int s) {
m_salary = s;
}
int get_salary() {
return m_salary;
}
};
int main()
{
Child c;
c.print1();
c.print2();
c.set_salary(100000);
std::cout << c.get_salary() << std::endl;
}
下一篇: 第二十九課 - 類別(Class)的多型(Polymorphism)
Last updated: