首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

高品質 C++/C 程式設計指南 第 8 章 (三):成員函數隱藏規則與破解之道

     編輯:關於C++

8.2.2 隱藏規則:繼承體系的隱形殺手

「隱藏」= 派生類函數**屏蔽**同名基類函數,規則極易誤判為重載或覆寫:

  1. 同名、參數不同 → **隱藏** (無論 virtual 與否),非重載。
  2. 同名、參數相同、基類**無 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 派生指標呼叫同名函數,行為截然不同** —— 這是隱藏規則最危險的副作用。

8.2.3 破解隱藏:using 宣告或轉發函數

問題

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*

解法 1:using 宣告引入基類同名函數

class Derived : public Base {
public:
    void f(char*);
    using Base::f; // 引入 Base::f(int),構成真正重載
};

解法 2:轉發函數 (舊標準無 using 時)

class Derived : public Base {
public:
    void f(char*);
    void f(int x) { Base::f(x); } // 手動轉發
};

隱藏規則存在的合理性

  1. 防止參數寫錯時編譯器靜默接受 (如 pd->f(10) 本意呼叫 Base::f(int) 卻誤綁定 Derived::f(char*)),隱藏讓錯誤**編譯期暴露**。
  2. 多重繼承時,若無隱藏,pd->f(10) 可能誤綁定非預期基類函數,隱藏消除此類意外。

**結論**:理解隱藏、善用 using,才能駕馭複雜繼承體系。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved