Item 33:避免隱藏繼承來的名稱

Item 33: Avoid hiding inherited names.

其實本文的話題和繼承完全沒有關係,隱藏名稱是作用域的問題。 在C++中每一對{ }都會開啓一個新的作用域,並嵌套在當前作用域中。

一個示例

int x;
void func(){
    double x;
    cin>>x;     // read a new value for local x
}

可以看到double x隱藏了int x,因爲C++的名稱隱藏規則(name-hiding rules)隱藏的是名稱,和類型無關!

繼承作用域

子類可以訪問父類中的名稱,是因爲子類的作用域是嵌套(nested in)在父類的作用域中的。 這一點也很符合直覺:

class Base{
public:
    void func_base();
};
class Derived{
public:
    void func_derived(){
        func_base();
    }
};

在func_derived()中調用func_base()時,編譯器首先檢查當前作用域內是否有名稱func_base(當然C++是不允許在函數裏定義函數的), 沒有找到;然後去父作用域Derived中尋找名稱func_base,仍然未找到;然後去再上一級作用域Base中尋找func_base,找到了!然後調用Base::func_base()。

如果還沒找到,編譯器還會去Derived所在命名空間下、全局作用域下尋找。

隱藏父類的名稱

子類中重寫(override)與父類方法同名的方法,將會隱藏父類中所有同名的重載方法。例如:

class Base{
public:
    virtual void func()=0;
    void func(int);
};
class Derived: public Base{
public:
    virtual void func();
};
...
Derived d;
d.func(1);      // Error!

Derived中聲明的func方法,隱藏了父類中所有的func名稱,包括所有的重載函數。

繼承所有重載方法

當你從父類繼承來了一系列的重載(overload)方法,而只想重寫(override)其中的一個時,可以用using,否則其他重載方法會被隱藏。

class Derived: public Base{
public:
    using Base::func;
    virtual void func();
};
...
d.func(1);      // OK

繼承一個重載方法

在public繼承中,子類和父類是”is-a”的關係(見Item 32),所以通常我們希望從父類繼承所有的方法。 但如果是private繼承(見Item 39), 可能你只想要其中的一個,這時可以定義一個轉發函數(forwarding function):

class Base{
public:
    virtual void mf1() = 0;
    virtual void mf1(int);
};
class Derived: private Base{
public:
    virtual void f1(){
        Base::mf1();        // 這是一個inline函數,見 Item30
    }
};

總結

  • 子類中的名稱會隱藏父類中所有同名的屬性。public繼承表示這”is-a”的關係,應該避免這樣做。
  • 使用using聲明或者轉發函數可以使父類名稱再次可見。

轉載地址:http://harttle.land/2015/09/06/effective-cpp-39.html
感謝作者 Harttle

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章