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

C++ 繼承時的名字遮蔽:同名成員函數不構成重載的深層機制

     編輯:C++ 基礎

名字遮蔽核心規則

派生類成員(變數/函數)與基類同名時,派生類成員遮蔽基類同名成員。遮蔽發生在名字查找階段,與參數列表無關。

成員函數遮蔽實戰

class People {
public: void show() { cout << "嗨,我叫" << m_name << endl; }
protected: char* m_name; int m_age;
};

class Student : public People {
public:
    void show() { cout << m_name << "年齡" << m_age << "成績" << m_score << endl; }  // 遮蔽
private: float m_score;
};

Student stu("小明",16,90.5);
stu.show();           // 調用 Student::show()
stu.People::show();   // 顯式調用基類版本

關鍵鐵律:基類與派生類同名函數不構成重載

不管參數列表如何不同,只要名字相同,派生類函數完全遮蔽基類所有同名函數。

經典反例

class Base {
public: void func(); void func(int);
};
class Derived : public Base {
public: void func(char*); void func(bool);  // 遮蔽 Base 所有 func!
};

Derived d;
d.func("str");   // OK: Derived::func(char*)
d.func(true);    // OK: Derived::func(bool)
d.func();        // 錯誤:Base::func() 被遮蔽,不可見
d.func(10);      // 錯誤:Base::func(int) 被遮蔽,不可見
d.Base::func();  // OK: 顯式指定調用基類版本

為什麼不構成重載?作用域嵌套機制

  • C++ 名字查找從內層作用域向外
  • 在 Derived 作用域找到 func → 停止查找,不再進入 Base 作用域
  • 重載解析僅在同一作用域進行
  • 不同類作用域的同名函數不同參與重載集合

解決方案:using 聲明引入基類名字

class Derived : public Base {
public:
    using Base::func;  // 將基類 func 引入 Derived 作用域
    void func(char*);
    void func(bool);
};
// 現在 d.func() 和 d.func(10) 可正常工作(參與重載解析)

成員變數遮蔽

class Base { protected: int x; };
class Derived : public Base { private: int x; };  // 遮蔽

Derived d;
d.x = 10;           // Derived::x
d.Base::x = 20;     // Base::x

遮蔽 vs 覆寫 vs 重載:三概念辨析

概念條件效果
遮蔽派生類同名成員(任意簽名)隱藏基類同名成員,名字查找停止
覆寫虛函數+同名同簽名+同返回類型運行時多態,動態綁定
重載同一作用域同名不同參數編譯期靜態綁定,參數匹配選擇

最佳實踐建議

  1. 避免無意遮蔽:命名規範區分基類/派生類成員
  2. 需要多態時:確保虛函數同名同簽名覆寫
  3. 需保留基類重載集合:使用 using Base::func;
  4. 故意遮蔽並阻止基類調用:可聲明為 private 或 delete

總結

名字遮蔽是 C++ 作用域嵌套名字查找規則的直接後果:內層同名阻斷外層查找。導致基類/派生類同名函數不構成重載,基類所有同名函數不可見。理解此機制,善用 using 聲明引入基類名字,是正確設計繼承體系、避免驚訝行為的關鍵。

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