向上轉型:將派生類物件/指針/引用賦值給基類物件/指針/引用。方向:派生 → 基(繼承圖向上)。安全、隱式、編譯器自動完成。
對應向下轉型:基 → 派,有風險,需顯式 dynamic_cast(後續章節)。
class A { int m_a; };
class B : public A { int m_b; };
A a(10);
B b(66, 99);
a = b; // 向上轉型:派生物件賦值給基類物件
賦值前: A: m_a=10 | B: m_a=66, m_b=99 賦值後: A: m_a=66 | B: m_a=66, m_b=99
m_a),切掉派生類新增成員(m_b)a.display() 仍調用 A::display()this 指針不變:仍指向 a 自身A* pa = new A(1); B* pb = new B(2, 20); D* pd = new D(4, 40, 400, 4000); // 多繼承:D : B, C pa = pd; // D* → A* pb = pd; // D* → B* pc = pd; // D* → C* (第二基類)
pa->display() // 輸出 A 版本,雖指向 D 物件 pb->display() // 輸出 B 版本 pc->display() // 輸出 C 版本
原因:非虛函數調用由指針靜態類型決定,非指向物件。
pa = 0x9b17f8 pb = 0x9b17f8 pc = 0x9b1800 // 不同於 pd! pd = 0x9b17f8
原因:多繼承物件佈局中,第二/後續基類子物件偏移非零。D* → C* 需調整指針地址(this 指針調整)。
D d(4, 40, 400, 4000); A& ra = d; B& rb = d; C& rc = d; ra.display(); // A 版本 rb.display(); // B 版本 rc.display(); // C 版本
引用無法重新綁定,需分別定義。行為與指針一致:成員變數訪問動態,非虛函數靜態綁定。
D 物件佈局 (假設無虛繼承): +------------------+ ← pd, pa, pb (地址相同) | A 部分 (m_a) | +------------------+ | B 部分 (m_b) | +------------------+ ← pb 實際指向此處 | C 部分 (m_c) | ← pc 指向此處 (偏移量 > 0) +------------------+ | D 部分 (m_d) | +------------------+
D* → A*/B*:地址不變(首基類優化)
D* → C*:地址 + 偏移量(編譯器自動調整)
通過基類物件/指針/引用只能訪問基類成員(含繼承而來),無法直接訪問派生類新增成員。需向下轉型(dynamic_cast)恢復完整訪問。
| 形式 | 切片 | 指針調整 | 函數綁定 | 用途 |
|---|---|---|---|---|
| 物件賦值 | 是 (切掉派生成員) | N/A | 靜態 (基類版本) | 值語義複製基類部分 |
| 指針賦值 | 否 | 多繼承時可能 (非首基類) | 非虛靜態/虛動態 | 多態、異構容器 |
| 引用賦值 | 否 | 同指針 | 同指針 | 多態參數傳遞 |
static_castdynamic_cast