| 機制 | 作用域 | 函數名 | 參數列表 | virtual | 關鍵點 |
|---|---|---|---|---|---|
| 重載 | 同一類 | 相同 | 不同(非隱式轉換) | 可有可無 | 編譯期靜態綁定 |
| 覆蓋 | 基類/派生類 | 相同 | 相同 | 基類必須有 | 運行期動態綁定,多態基石 |
| 隱藏 | 基類/派生類 | 相同 | 任意 | 視情況 | 派生類同名函數屏蔽基類同名函數 |
virtual,**基類函數被隱藏**(非覆蓋)
#include <iostream>
using std::cout; using std::endl;
class Base {
public:
virtual void f(float x) { cout << "Base::f(float) " << x << endl; }
void g(float x) { cout << "Base::g(float) " << x << endl; }
void h(float x) { cout << "Base::h(float) " << x << endl; }
};
class Derived : public Base {
public:
virtual void f(float x) { cout << "Derived::f(float) " << x << endl; } // 覆蓋
void g(int x) { cout << "Derived::g(int) " << x << endl; } // 隱藏 Base::g(float)
void h(float x) { cout << "Derived::h(float) " << x << endl; } // 隱藏 Base::h(float)
};
int main() {
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 靜態綁定,Base::g 非 virtual
pd->g(3.14f); // Derived::g(int) 3 隱藏發生,float→int 隱式轉換
pb->h(3.14f); // Base::h(float) 3.14 靜態綁定,Base::h 非 virtual
pd->h(3.14f); // Derived::h(float) 3.14 隱藏發生
}
Derived::f(float) 3.14
Derived::f(float) 3.14
Base::g(float) 3.14
Derived::g(int) 3
Base::h(float) 3.14
Derived::h(float) 3.14
f:基類 virtual,派生類覆蓋 → 多態生效g:基類無 virtual,派生類參數不同 → 隱藏。pb->g 調用基類;pd->g 只能看到派生類版本,float 隱式轉 inth:基類無 virtual,派生類同名同參 → 隱藏。pb->h 調用基類;pd->h 調用派生類
class Base { public: void CheckType() { cout << "Base Ptr" << endl; } };
class Derived : public Base { public: void CheckType() { cout << "Derived Ptr" << endl; } };
int main() {
Derived d;
Base* pb = &d;
Derived* pd = &d;
pb->CheckType(); // Base Ptr
pd->CheckType(); // Derived Ptr
}
此時隱藏行為被有意利用,但屬於「技巧」而非常規設計。
virtual(除非確定不作多態刪除)virtualoverride (C++11),編譯器會檢查簽名匹配using Base::func; 在派生類中引入基類同名函數,避免隱藏:
class Derived : public Base {
public:
using Base::g; // 引入 Base::g(float),與 Derived::g(int) 構成真正重載
void g(int x) { ... }
};
此時 pd->g(3.14f) 會正確調用 Base::g(float)。