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

C++ 名稱遮蔽機制詳解:派生類別如何正確繼承基類虛擬多載函式

     編輯:關於C++

問題重現

class B {
    virtual void test() { std::cout << "B::test()\n"; }
    virtual void test(int x) { std::cout << "B::test(int)\n"; }
};

class D : public B {
    virtual void test() { std::cout << "D::test()\n"; }  // 僅覆寫無參數版
};

int main() {
    D d;
    d.test();     // OK
    d.test(17);   // 編譯錯誤:C2660 'test' function does not take 1 parameters
}

根本原因:名稱查找與遮蔽規則

C++ 名稱查找遵循「由內而外」原則:

  1. 編譯器在 D 類別作用域找到 test 名稱。
  2. 查找**立即停止**,不再搜尋基類 B。
  3. 在 D 中僅找到 test(),參數不匹配 test(17),報錯。

這稱為**名稱遮蔽**,非多載解析失敗。標準設計意圖:避免在深層繼承鏈中意外匹配到語意不符的多載版本。

解決方案一:顯式引入基類成員

class D : public B {
public:
    using B::test;  // 將 B 所有 test 多載引入 D 作用域
    virtual void test() { std::cout << "D::test()\n"; }
};

優點: 基類新增 test(double) 等多載自動繼承,無需修改 D。
缺點: 所有基類 test 多載皆公開,若需隱藏特定版本需額外處理。

解決方案二:顯式轉發函式

class D : public B {
public:
    virtual void test(int x) { B::test(x); }  // 手動轉發
    virtual void test() { std::cout << "D::test()\n"; }
};

優點: 精確控制公開哪些多載版本。
缺點: 基類新增多載時需同步更新衍生類別。

進階應用:結合 private 繼承與 using 保護封裝

class B {
public:
    void func1();
    void func2(double);
    virtual void test();
    virtual void test(int);
};

class D : private B {  // 完全隱藏 B 介面
public:
    using B::test;     // 僅選擇性公開 test 多載集合
};

此技巧常用於「介面繼承」而非「實作繼承」場景。

核心觀念總結

  • 多載 發生在**同一作用域**;覆寫 發生在**基底/衍生類別**之間。
  • 衍生類別宣告**任何同名函式**皆會遮蔽基類**所有同名多載**。
  • using Base::Func 是標準、優雅的解除遮蔽方式。
  • 若需隱藏特定多載,採用轉發函式或調整存取指定符。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved