繼承體系中,衍生類同名函數可能構成**覆寫**、**隱藏**或**多載**,三者語意迥異。本文詳細釐清:覆寫需 virtual 且簽章完全相同;隱藏發生於非虛函數同名或參數不同;多載僅限同一類別內。附贈多層繼承覆寫/隱藏混合案例與呼叫基類隱藏函數語法。
class Animal {
public:
virtual void breathe() { cout << "animal breathe\n"; }
};
class Fish : public Animal {
public:
void breathe() { cout << "fish bubble\n"; } // 覆寫
};
virtual。編譯器產生 **vtable**,運行時依物件動態型別決定呼叫哪個版本 (遲綁定/動態綁定)。
class Animal { public: void breathe() { cout << "animal breathe\n"; } };
class Fish : public Animal { public: void breathe() { cout << "fish bubble\n"; } };
Fish::breathe **隱藏** Animal::breathe。透過 Animal* 指向 Fish 物件呼叫 breathe(),**仍呼叫基類版本** (早期綁定)。
class Base { public: virtual void fn(); };
class Derived : public Base { public: void fn(int); }; // 隱藏 Base::fn()
Derived::fn(int) 隱藏 Base::fn()。衍生類物件**無法直接呼叫** fn() (編譯錯誤:找不到無參版本)。
| 特性 | 覆寫 | 隱藏 | 多載 |
|---|---|---|---|
| 發生範圍 | 基類 ↔ 衍生類 | 基類 ↔ 衍生類 | 同一類別內 |
| 基類需 virtual | 是 | 否 (有無皆可) | 不適用 |
| 函數簽章 | 完全相同 | 同名 (參數可異) | 參數列表不同 |
| 綁定時機 | 運行時 (動態) | 編譯時 (靜態) | 編譯時 (靜態) |
| 多態效果 | 有 | 無 | 無 |
class Base { public: virtual void fn(); };
class Derived : public Base { public: void fn(int); }; // 隱藏 Base::fn()
class Derived2 : public Derived { public: void fn(); }; // 覆寫 Base::fn()!
Derived::fn(int) 隱藏 Base::fn() (非虛)。Derived2::fn() 與 Base::fn() 簽章相同 → **覆寫** Base::fn() (即使 Derived 中被隱藏)。Derived2 物件透過 Base* 呼叫 fn() → 動態綁定到 Derived2::fn()。
class Derived : public Base {
public:
void fn(int) {
Base::fn(); // 明確指定基類作用域
}
};
語法:**BaseClassName::FunctionName(args)**。
「同名同參看 virtual:有 virtual 是覆寫 (多態),無 virtual 是隱藏 (靜態)。同名不同參一律隱藏。多載只發生在同一個類別裡。」
#include
using namespace std;
class Base {
public:
virtual void xfn(int i) { cout << "Base::xfn(int)\n"; }
void yfn(float f) { cout << "Base::yfn(float)\n"; }
void zfn() { cout << "Base::zfn()\n"; }
};
class Derived : public Base {
public:
void xfn(int i) { cout << "Derived::xfn(int)\n"; } // 覆寫
void yfn(int c) { cout << "Derived::yfn(int)\n"; } // 隱藏 yfn(float)
void zfn() { cout << "Derived::zfn()\n"; } // 隱藏 zfn()
};
int main() {
Derived d;
Base* pB = &d;
Derived* pD = &d;
pB->xfn(5); // Derived::xfn(int) (虛函數動態綁定)
pD->xfn(5); // Derived::xfn(int)
pB->yfn(3.14f); // Base::yfn(float) (靜態綁定,指標型別為 Base*)
pD->yfn(3.14f); // Derived::yfn(int) (隱藏,float 隱性轉 int)
pB->zfn(); // Base::zfn() (非虛,靜態綁定)
pD->zfn(); // Derived::zfn() (隱藏)
}
覆寫是多態基石,**必須** virtual + **完全相同簽章**。隱藏是靜態綁定陷阱,**同名即隱藏** (含參數不同)。設計介面時:基類公開函數**預設加 virtual**,衍生類覆寫**加上 override (C++11)** 讓編譯器檢查簽章一致,徹底杜絕隱藏導致的靜態綁定 Bug。