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

C++ 成員函數重載、覆蓋、隱藏與 virtual 關鍵字深度解析

     編輯:關於C++

核心概念辨析

機制作用域函數名參數列表virtual關鍵點
重載同一類相同不同(非隱式轉換)可有可無編譯期靜態綁定
覆蓋基類/派生類相同相同基類必須有運行期動態綁定,多態基石
隱藏基類/派生類相同任意視情況派生類同名函數屏蔽基類同名函數

隱藏規則詳解

  1. 同名不同參:派生類函數與基類函數同名但參數不同,**無論基類是否 virtual**,基類函數被隱藏(非重載,因作用域不同)
  2. 同名同參無 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 隱式轉 int
  • h:基類無 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
}

此時隱藏行為被有意利用,但屬於「技巧」而非常規設計。

最佳實踐總結

  1. 基類析構函數必須 virtual(除非確定不作多態刪除)
  2. 預期被覆蓋的函數必須加 virtual
  3. 派生類覆蓋時建議加 override (C++11),編譯器會檢查簽名匹配
  4. 避免同名不同參**跨作用域**,易引發隱藏困惑;若需區分,改用不同函數名
  5. 使用 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)。

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