「隱藏」= 派生類函數**屏蔽**同名基類函數,規則極易誤判為重載或覆寫:
virtual 與否),非重載。virtual** → **隱藏**,非覆寫。class Base {
public:
virtual void f(float x) { cout << "Base::f(float) " << x; }
void g(float x) { cout << "Base::g(float) " << x; }
void h(float x) { cout << "Base::h(float) " << x; }
};
class Derived : public Base {
public:
virtual void f(float x) { cout << "Derived::f(float) " << x; } // 覆寫
void g(int x) { cout << "Derived::g(int) " << x; } // 隱藏 Base::g(float)
void h(float x) { cout << "Derived::h(float) " << x; } // 隱藏 Base::h(float) (基類無 virtual)
};
Derived d;
Base* pb = &d;
Derived* pd = &d;
pb->f(3.14f); // Derived::f(float) 3.14 ✅ 多態正常
pd->f(3.14f); // Derived::f(float) 3.14 ✅
pb->g(3.14f); // Base::g(float) 3.14 ❌ 隱藏導致靜態綁定
pd->g(3.14f); // Derived::g(int) 3 ⚠️ 參數隱式轉 float→int!
pb->h(3.14f); // Base::h(float) 3.14 ❌ 隱藏導致靜態綁定
pd->h(3.14f); // Derived::h(float) 3.14 ✅
**同一物件,透過基類指標 vs 派生指標呼叫同名函數,行為截然不同** —— 這是隱藏規則最危險的副作用。
class Base { public: void f(int); };
class Derived : public Base { public: void f(char*); };
Derived* pd = new Derived;
pd->f(10); // ❌ 編譯錯誤:Base::f(int) 被 Derived::f(char*) 隱藏,10 無法隱式轉 char*
class Derived : public Base {
public:
void f(char*);
using Base::f; // 引入 Base::f(int),構成真正重載
};
class Derived : public Base {
public:
void f(char*);
void f(int x) { Base::f(x); } // 手動轉發
};
pd->f(10) 本意呼叫 Base::f(int) 卻誤綁定 Derived::f(char*)),隱藏讓錯誤**編譯期暴露**。pd->f(10) 可能誤綁定非預期基類函數,隱藏消除此類意外。**結論**:理解隱藏、善用 using,才能駕馭複雜繼承體系。