天天看點

C++隐藏規則再分析

一.序言

前面一篇區分了重載/覆寫/隐藏,那麼這一篇先給一個magic的例子。

class Base
{
    public:
        virtual void f(float a){cout<<"Base::f_float"<<endl;}
        void g(float a){cout<<"Base::g_float"<<endl;}
        void h(float x){cout<<"Base::h_float"<<endl;}

};
class Der : public Base
{
    public:
        void f(float a){cout<<"Der::f_float"<<endl;}
        void g(int a){cout<<"Der::g_int"<<endl;}
        void h(float a){cout<<"Der::h_float"<<endl;}
};
int main()
{
    Der d;
    Base *pb = &d;
    Der *pd = &d;
    pb->f();//Der::f_float,覆寫
    pd->f();//Der::f_float,正常
    cout<<"--------------->"<<endl;
    pb->g();//Base::g_float,這就是隐藏與覆寫的差別,如果是覆寫的情況的話,列印出來的應是Der::g_int.由于是父類指針調用父類的g函數,隐藏隻是子類的方法隐藏父類,當子類調用時,不受父類同名方法的影響;
    pd->g();//Der::g_int,隐藏
    cout<<"--------------->"<<endl;
    pb->h();//Base::h_float,同pb->g(3.14f)情況
    pd->h();//Der::h_float,隐藏
}
           

先看結果

C++隐藏規則再分析

每種情況的分析請見代碼

二.隐藏規則存在的意義

class Base
{
public:
    void f(int x){cout<<"Base::f_int"<<endl;};
};
class Der : public Base
{
public:
    void f(char *str){cout<<"Der::f_char*"<<endl;}
};
int main()
{
    Der d;
    d.f();//error,從類型‘int’到類型‘char*’的轉換無效
}
           

也許你的本義是想調用函數Base::f(int a),但是它被隐藏掉了。由于整型10不能隐式的轉化成char*類型,是以編譯時報錯。

但是你不能因為這就說C++的隐藏特性沒有用。給出理由:

(1)也許我本來就是想調用Der::f(char *str);恰好因為C++的隐藏規則指出了我的錯誤。

(2)如果Der類繼承了多個父類(多重繼承),最後誰也不知道哪個父類裡定義了f函數,如果沒有隐藏規則,會很莫名其妙的調用某個f函數。隐藏可以避免這些意外的發生

如果一定要調用Base::f(int),可以這樣修改代碼

class Der : public Base
{
public:
    void f(char *str){cout<<"Der::f_char*"<<endl;}
    void f(int a){Base::f(a);}
};
           

繼續閱讀