C++繼承基礎:子類如何繼承父類成員

在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) 三種,它們在子類中的訪問規則不同:

  1. public 成員變量:子類可以直接訪問。
    例如:Dog 類繼承了 Animalnameage,所以在 Dog 中可以直接使用 nameage
   Dog myDog;
   myDog.name = "Buddy";  // 直接訪問父類的public成員
   myDog.age = 3;         // 直接訪問父類的public成員
  1. private 成員變量:子類不能直接訪問,但可以通過父類提供的公開接口(如 setWeight/getWeight)間接操作。
    例如:Animalweight 是 private,子類 Dog 不能直接寫 myDog.weight,但可以調用 myDog.setWeight(15) 來設置體重。

  2. protected 成員變量:僅子類和子類的子類可以直接訪問(初學者暫時不用深入,瞭解即可)。

三、子類如何繼承父類的成員函數

與成員變量類似,父類的成員函數也分不同權限,子類的訪問規則如下:

  1. public 成員函數:子類可以直接調用。
    例如:Animaleat()sleep() 是 public,子類 Dog 可以直接調用 myDog.eat()myDog.sleep()

  2. private 成員函數:子類不能直接調用,需通過父類的公開接口間接調用(同私有變量邏輯)。

  3. 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 成員需通過公開接口間接訪問,保證數據封裝性。
- 構造函數需顯式調用父類構造函數,通過初始化列表完成父類部分的初始化。

通過繼承,我們可以用更少的代碼實現更復雜的功能,比如“貓”“鳥”等類都可以繼承“動物”類,只需添加各自特有的方法(如 CatcatchMouse())。

小練習:嘗試定義一個 Cat 類繼承 Animal,並添加 catchMouse() 方法,然後創建 Cat 對象測試繼承效果。

小夜