繼承讓子類別 (派生類別) 取得父類別 (基底類別) 的資料與操作,僅需擴充特有功能。以「交通工具」為基底類別,共同屬性為速度與載客數;「汽車」衍生出排氣量,「飛機」衍生出翼展。程式碼如下:
#include <iostream>
using namespace std;
class Vehicle {
public:
void EditSC(float speed, int total);
protected:
float speed; // 速度
int total; // 最大載客量
};
void Vehicle::EditSC(float speed, int total) {
Vehicle::speed = speed;
Vehicle::total = total;
}
class Car : public Vehicle { // 公有繼承
public:
Car() { aird = 0; }
protected:
int aird; // 排氣量
};
class Plane : public Vehicle {
protected:
float wingspan; // 翼展
};
void main() {
Car a;
a.EditSC(150, 4); // 呼叫基底類別方法
cin.get();
}
派生類別物件在記憶體中包含基底類別子物件。建立 Car 物件時,this 指標涵蓋 Vehicle 部分,故可直接存取基底成員。這也是 C++ 區別於 Java/C# 的關鍵:C++ 讓開發者理解物件模型的記憶體實況。
class Vehicle {
public:
Vehicle(float s=0, int t=0) { cout << "Vehicle 建構" << endl; }
~Vehicle() { cout << "Vehicle 解構" << endl; }
};
class Car : public Vehicle {
public:
Car(float a=0, float s=0, int t=0) : Vehicle(s, t) { // 呼叫基底建構函式
cout << "Car 建構" << endl;
aird = a;
}
~Car() { cout << "Car 解構" << endl; }
protected:
float aird;
};
void main() {
Car a(250, 150, 4); // 輸出:Vehicle 建構 → Car 建構
}
初始化清單 : Vehicle(s, t) 必須用於呼叫基底建構函式,否則會先呼叫基底預設建構函式再賦值,效率較低。
Car(const Car& temp) : Vehicle(temp.speed, temp.total) { // 必須顯式複製基底成員
aird = temp.aird;
}
編譯器不會自動呼叫基底拷貝建構函式,若省略 Vehicle(temp.speed, temp.total),基底成員將不被複製,導致資料遺失。
與建構順序相反,先執行派生類別解構函式,再執行基底解構函式,確保資源正確釋放。
class Motor { // 發動機類別
public:
Motor(char* m) { motortype = m; }
char* GetType() { return motortype; }
private:
char* motortype;
};
class Car : public Vehicle { // 繼承 Vehicle
public:
Car(float s, int t, float a, char* mt) : Vehicle(s, t), motor(mt) { // 組合 Motor
aird = a;
}
Motor GetMotor() { return motor; }
private:
float aird;
Motor motor; // 組合:Car 有 Motor
};
Car 是 Vehicle,可隱性轉型傳遞給需 Vehicle& 的函式。Car 有 Motor,無隱性轉型,需透過成員函式存取。設計原則:優先使用組合,僅當確立「是一種」關係且需多型時使用繼承。