(點擊此處,接上篇)
這一行為背後的根本原因是為了防止“當你在一個 library 或者 application framework 中建立一個新的 derived class 時,偶然地發生從遙遠的 base classes 繼承 overloads 的情況”。不幸的是,一般情況下你是需要繼承這些 overloads 的。實際上,如果你使用了 public inheritance 而又沒有繼承這些 overloads,你就違反了 Item 32 講解的“base 和 derived classes 之間是 is-a 關係”這一 public inheritance 的基本原則。在這種情況下,你幾乎總是要繞過 C++ 對“通過繼承得到的名字”的預設的覆蓋機制。
你可以用 using declarations 做到這一點:
class Base {
private:
int x;
public:
virtual void mf1() = 0;
virtual void mf1(int);
virtual void mf2();
void mf3();
void mf3(double);
...
};
class Derived: public Base {
public:
using Base::mf1; // make all things in Base named mf1 and mf3
using Base::mf3; // visible (and public) in Derived's scope
virtual void mf1();
void mf3();
void mf4();
...
};
現在 inheritance 就可以起到預期的作用:
Derived d;
int x;
...
d.mf1(); // still fine, still calls Derived::mf1
d.mf1(x); // now okay, calls Base::mf1
d.mf2(); // still fine, still calls Base::mf2
d.mf3(); // fine, calls Derived::mf3
d.mf3(x); // now okay, calls Base::mf3
這意味著如果你從一個帶有重載函數的 base class 繼承,而且你只想重定義或替換它們中的一部分,你需要為每一個你不想覆蓋的名字使用 using declaration。如果你不這樣做,一些你希望繼承下來的名字會被覆蓋。
可以想象在某些時候你不希望從你的 base classes 繼承所有的函數。在 public inheritance 中,這是絕不會發生的,這還是因為,它違反了 public inheritance 在 base 和 derived classes 之間的 is-a 關係。(這就是為什麼上面的 using declarations 在 derived class 的 public 部分:在 base class 中是 public 的名字在公有繼承的 derived class 中也應該是 public。)然而,在 private inheritance(參見 Item 39)中,它還是有意義的。例如,假設 Derived 從 Base 私人繼承,而且 Derived 只想繼承沒有參數的那個 mf1 的版本。在這裡,using declaration 沒有這個本事,因為一個 using declaration 會使得所有具有給定名字的函數在 derived class 中可見。不,這裡是使用了一種不同的技術的情形,即,一個簡單的 forwarding function(轉調函數):
class Base {
public:
virtual void mf1() = 0;
virtual void mf1(int);
... // as before
};
class Derived: private Base {
public:
virtual void mf1() // forwarding function; implicitly
{ Base::mf1(); } // inline (see Item 30)
...
};
...
Derived d;
int x;
d.mf1(); // fine, calls Derived::mf1
d.mf1(x); // error! Base::mf1() is hidden
forwarding function(轉調函數)的另一個功效是用於老式的編譯器,它們(不正確地)不支援用 using declarations 將“通過繼承得到的名字”引入到 derived class 的範圍。
這就是關於 inheritance 和 name hiding 的全部故事,但是當 inheritance 與 templates 結合起來,“通過繼承得到的名字被隱藏”的問題會以一種全然不同的形式呈現出來。關於全部 angle-bracket-demarcated(邊邊角角)的細節,參見 Item 43。
Things to Remember
- derived classes 中的名字覆蓋 base classes 中的名字,在 public inheritance 中,這從來不是想要的。
- 為了使隱藏的名字重新可見,使用 using declarations 或者 forwarding functions(轉調函數)。