在C++中,繼承是面向對象編程的重要特性之一。它允許一個類(我們稱之爲子類或派生類)通過“繼承”另一個類(我們稱之爲父類或基類)的成員(成員變量和成員函數),從而複用已有代碼並擴展功能。想象一下,如果我們有一個“動物”類,裏面包含“喫飯”“睡覺”這些通用行爲,那麼“狗”“貓”等具體動物類就可以直接繼承“動物”類,無需重複編寫這些通用代碼。
一、如何定義父類和子類¶
首先,我們需要定義一個父類,再定義一個子類來繼承它。以“動物”和“狗”爲例:
// 父類:Animal(動物)
class Animal {
public:
string name; // 動物的名字(公開成員,子類可直接訪問)
int age; // 動物的年齡(公開成員,子類可直接訪問)
// 喫飯的方法(公開成員函數,子類可直接調用)
void eat() {
cout << name << " is eating." << endl;
}
// 睡覺的方法(公開成員函數,子類可直接調用)
void sleep() {
cout << name << " is sleeping." << endl;
}
private:
int weight; // 體重(私有成員,子類不可直接訪問)
public:
// 通過公開接口設置體重(間接訪問私有成員)
void setWeight(int w) {
weight = w;
}
int getWeight() {
return weight;
}
};
// 子類:Dog(狗),繼承自Animal
class Dog : public Animal { // public繼承:父類成員在子類中的訪問權限保持原樣
public:
// 狗特有的方法(子類新增的成員)
void bark() {
cout << name << " is barking!" << endl;
}
};
二、子類如何繼承父類的成員變量¶
父類的成員變量分爲 公開(public)、保護(protected) 和 私有(private) 三種,它們在子類中的訪問規則不同:
- public 成員變量:子類可以直接訪問。
例如:Dog類繼承了Animal的name和age,所以在Dog中可以直接使用name和age。
Dog myDog;
myDog.name = "Buddy"; // 直接訪問父類的public成員
myDog.age = 3; // 直接訪問父類的public成員
-
private 成員變量:子類不能直接訪問,但可以通過父類提供的公開接口(如
setWeight/getWeight)間接操作。
例如:Animal的weight是 private,子類Dog不能直接寫myDog.weight,但可以調用myDog.setWeight(15)來設置體重。 -
protected 成員變量:僅子類和子類的子類可以直接訪問(初學者暫時不用深入,瞭解即可)。
三、子類如何繼承父類的成員函數¶
與成員變量類似,父類的成員函數也分不同權限,子類的訪問規則如下:
-
public 成員函數:子類可以直接調用。
例如:Animal的eat()和sleep()是 public,子類Dog可以直接調用myDog.eat()或myDog.sleep()。 -
private 成員函數:子類不能直接調用,需通過父類的公開接口間接調用(同私有變量邏輯)。
-
protected 成員函數:僅子類可以直接調用(初學者瞭解即可)。
int main() {
Dog myDog;
myDog.name = "Buddy";
myDog.age = 3;
myDog.eat(); // 調用父類的public成員函數(正常輸出)
myDog.bark(); // 調用子類新增的成員函數(輸出 "Buddy is barking!")
myDog.sleep(); // 調用父類的public成員函數(正常輸出)
myDog.setWeight(15); // 通過父類的接口設置private成員
cout << "Weight: " << myDog.getWeight() << endl; // 輸出 15
return 0;
}
四、不同繼承方式的影響¶
C++ 有三種繼承方式,會影響子類對父類成員的訪問權限:
| 繼承方式 | 父類 public 成員在子類中的權限 | 父類 protected 成員在子類中的權限 | 父類 private 成員在子類中的權限 |
|---|---|---|---|
| public | public | protected | 不可見(無法直接訪問) |
| private | private | private | 不可見 |
| protected | protected | protected | 不可見 |
初學者注意:
- 最常用的是 public 繼承(默認不寫時也可視爲 public,但建議顯式寫出),此時父類的 public 和 protected 成員在子類中保持原權限,private 成員不可見。
- 其他兩種方式(private/protected 繼承)通常用於特殊場景(如隱藏父類接口),初學者可暫時忽略。
五、構造函數的繼承與初始化¶
父類的構造函數不能被直接繼承,但子類構造函數必須先初始化父類部分。例如,Animal 有一個構造函數:
class Animal {
public:
string name;
int age;
Animal(string n, int a) : name(n), age(a) { // 父類構造函數
cout << "Animal " << name << " created." << endl;
}
};
子類 Dog 構造時,需通過初始化列表調用父類構造函數:
class Dog : public Animal {
public:
// 子類構造函數:先調用父類構造函數,再初始化自己
Dog(string n, int a) : Animal(n, a) { // 必須先調用父類構造函數
cout << "Dog " << n << " created." << endl;
}
};
關鍵點:子類對象創建時,會先執行父類構造函數,再執行子類構造函數。
六、總結¶
繼承的核心是 代碼複用 和 擴展:
- 子類可以直接繼承父類的 public/protected 成員(變量/函數),避免重複編寫通用邏輯。
- 父類的 private 成員需通過公開接口間接訪問,保證數據封裝性。
- 構造函數需顯式調用父類構造函數,通過初始化列表完成父類部分的初始化。
通過繼承,我們可以用更少的代碼實現更復雜的功能,比如“貓”“鳥”等類都可以繼承“動物”類,只需添加各自特有的方法(如 Cat 的 catchMouse())。
小練習:嘗試定義一個 Cat 類繼承 Animal,並添加 catchMouse() 方法,然後創建 Cat 對象測試繼承效果。