[C++] 名稱查找

1. 本地名稱和全局名稱

我們都知道在諸如這般的代碼中:

// global變量
int x;
void someFunc(){

    // local變量
    double x;

    // 讀一個(gè)新值賦予local變量x
    std::cin >> x;
}

這個(gè)讀取數(shù)據(jù)的語(yǔ)句指涉的是local變量x音诈,而不是global變量x幻碱,
因?yàn)閮?nèi)層作用域的名稱會(huì)遮掩(遮蔽)外圍作用域的名稱绎狭。

當(dāng)編譯器處于someFunc的作用域內(nèi)并遭遇名稱x時(shí),
它在local作用域內(nèi)查找是否有什么東西帶著這個(gè)名稱褥傍,
如果找到就不再找其他作用域儡嘶。
本例的someFunc的x是double類型而global x是int類型,但那不要緊恍风。
C++的名稱遮掩規(guī)則(name-hiding rule)所做的唯一事情就是蹦狂,遮掩名稱。
至于名稱是否應(yīng)和相同或不同的類型朋贬,并不重要凯楔。

本例中一個(gè)名為x的double遮掩了一個(gè)名為x的int。

2. 子類中的名稱和父類中的名稱

現(xiàn)在導(dǎo)入繼承兄世,我們知道啼辣,當(dāng)位于一個(gè)derived class成員函數(shù)內(nèi)指涉(refer to) base class內(nèi)的某物(也許是個(gè)成員函數(shù)啊研,typedef御滩,或成員變量)時(shí),
編譯器可以找出我們所指涉的東西党远,因?yàn)閐ervied class繼承了聲明于base class內(nèi)的所有東西削解。
實(shí)際運(yùn)作方式是,derived class作用域被嵌套在base class作用域內(nèi)沟娱。

class Base{
private:
    int x;

public:
    virtual void mf1() = 0;
    virtual void mf2(); 
    void mf3();
    ...
};

class Dervied: public Base{
public:
    virtual void mf1();
    void mf4();
    ...
};

此例內(nèi)含一組混合了public和private名稱氛驮,以及一組成員變量和成員函數(shù)名稱。
這些成員函數(shù)包括pure virtual济似,impure virtual和non-virtual三種矫废,
這是為了強(qiáng)調(diào)我們談的是名稱,和其他無(wú)關(guān)砰蠢。
這個(gè)例子也可以加入各種名稱類型蓖扑,例如enum,nested class和typedef台舱。
整個(gè)討論中唯一重要的是這些東西的名稱律杠,至于這些東西是什么并不重要。
本例使用單一繼承竞惋,然而一旦了解單一繼承下發(fā)生的事柜去,很容易就可以推想C++在多重繼承下的行為。

假設(shè)dervied class內(nèi)的mf4的實(shí)現(xiàn)碼部分像這樣:

void Derived::mf4(){
    ...
    mf2();
    ...
}

當(dāng)編譯器看到這里使用名稱mf2拆宛,必須估算它指涉(refer to)什么東西嗓奢。
編譯器的做法是查找各作用域,看看有沒(méi)有某個(gè)名為mf2的聲明式浑厚。

首先查找local作用域(也就是mf4覆蓋的作用域)蔓罚,在那沒(méi)找到任何東西名為mf2椿肩,
于是查找其外圍作用域,也就是class Derived覆蓋的作用域豺谈,還是沒(méi)找到任何東西名為mf2郑象,于是再往外圍移動(dòng),本例為Base class茬末。
在那兒編譯器找到一個(gè)名為mf2的東西了厂榛,于是停止查找。

如果Base內(nèi)還是沒(méi)有mf2丽惭,查找動(dòng)作便繼續(xù)下去击奶,
首先找內(nèi)含Base的那個(gè)namespace的作用域(如果有的話),最后往global作用域找去责掏。

3. 遮掩父類名稱

再次考慮前一個(gè)例子柜砾,這次讓我們重載mf1和mf3,并且添加一個(gè)新版mf3到Dervied去换衬。
Derived重載了mf3痰驱,那是一個(gè)繼承而來(lái)的non-virtual函數(shù),
這會(huì)使整個(gè)設(shè)計(jì)立刻顯得疑云重重瞳浦。
但為了充分認(rèn)識(shí)繼承體系內(nèi)的“名稱可視性”担映,我們暫時(shí)安之若素。

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:
    virtual void mf1();
    void mf3();
    void mf4();
    ...
};

這段代碼的行為會(huì)讓每一位第一次面對(duì)它的C++程序員大吃一驚叫潦。
以作用域?yàn)榛A(chǔ)的“名稱遮掩規(guī)則”并沒(méi)有改變蝇完,因此base class內(nèi)所有名為mf1和mf3的函數(shù)都被derived class內(nèi)的mf1和mf3函數(shù)遮掩掉了。
從名稱查找觀點(diǎn)來(lái)看矗蕊,Base::mf1Base::mf3不再被Derived繼承短蜕。

Derived d;
int x;
...

// 沒(méi)問(wèn)題,調(diào)用Derived::mf1
d.mf1();

// 錯(cuò)誤傻咖,因?yàn)镈erived::mf1遮掩了Base::mf1
d.mf1(x);

// 沒(méi)問(wèn)題朋魔,調(diào)用Base::mf2
d.mf2();

// 沒(méi)問(wèn)題,調(diào)用Derived::mf3
d.mf3();

// 錯(cuò)誤没龙,因?yàn)镈erived::mf3遮掩了Base::mf3
d.mf3(x);

如你所見(jiàn)铺厨,上述規(guī)則都適用,即使base class和derived class內(nèi)的函數(shù)有不同的參數(shù)類型也適用硬纤,
而且不論函數(shù)是virtual或non-virtual一體適用解滓。
這和上文一開(kāi)始展示的道理相同,當(dāng)時(shí)函數(shù)someFunc內(nèi)的double x遮掩了global作用域內(nèi)的int x筝家,
如今Derived內(nèi)的函數(shù)mf3遮掩了一個(gè)名為mf3但類型不同的Base函數(shù)洼裤。

4. using聲明

不幸的是,你通常會(huì)想繼承重載函數(shù)溪王,
實(shí)際上腮鞍,如果你正在使用public繼承而又不繼承那些重載函數(shù)值骇,就是違反了base和derived class之間的is-a關(guān)系,
而is-a關(guān)系是public繼承的基石移国。
因此吱瘩,你幾乎總會(huì)想要推翻(override)C++對(duì)“繼承而來(lái)的名稱”的缺省遮掩行為。

你可以使用using聲明式達(dá)成目標(biāo):

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:
    // 讓Base class內(nèi)名為mf1和mf3的所有東西迹缀,
    // 在Derived作用域內(nèi)都可見(jiàn)(并且public)
    using Base::mf1;
    using Base::mf3;

    virtual void mf1();
    void mf3();
    void mf4();
    ...
};

現(xiàn)在繼承機(jī)制一如往昔的運(yùn)作:

Derived d;
int x;
...

// 仍然沒(méi)問(wèn)題使碾,仍然調(diào)用Derived::mf1
d.mf1();

// 現(xiàn)在沒(méi)問(wèn)題了,調(diào)用Base::mf1
d.mf1(x);

// 仍然沒(méi)問(wèn)題祝懂,仍然調(diào)用Base::mf2
d.mf2();

// 沒(méi)問(wèn)題票摇,調(diào)用Derived::mf3
d.mf3();

// 現(xiàn)在沒(méi)問(wèn)題了,調(diào)用Base::mf3
d.mf3(x);

這意味如果你繼承base class并加上重載函數(shù)砚蓬,而你又希望重新定義或覆寫(xiě)(推翻)其中一部分矢门,
那么你必須為那些原本會(huì)被遮掩的每個(gè)名稱引入一個(gè)using聲明式,否則某些你希望繼承的名稱會(huì)被遮掩灰蛙。


Effective C++ - P156

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末祟剔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缕允,更是在濱河造成了極大的恐慌峡扩,老刑警劉巖蹭越,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件障本,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡响鹃,警方通過(guò)查閱死者的電腦和手機(jī)驾霜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)买置,“玉大人粪糙,你說(shuō)我怎么就攤上這事》尴睿” “怎么了蓉冈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)轩触。 經(jīng)常有香客問(wèn)我寞酿,道長(zhǎng),這世上最難降的妖魔是什么脱柱? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任伐弹,我火速辦了婚禮,結(jié)果婚禮上榨为,老公的妹妹穿的比我還像新娘惨好。我一直安慰自己煌茴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布日川。 她就那樣靜靜地躺著蔓腐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪龄句。 梳的紋絲不亂的頭發(fā)上合住,一...
    開(kāi)封第一講書(shū)人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音撒璧,去河邊找鬼透葛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛卿樱,可吹牛的內(nèi)容都是我干的僚害。 我是一名探鬼主播,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼繁调,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼萨蚕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起蹄胰,我...
    開(kāi)封第一講書(shū)人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岳遥,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后裕寨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體浩蓉,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年宾袜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捻艳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡庆猫,死狀恐怖认轨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情月培,我是刑警寧澤嘁字,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站杉畜,受9級(jí)特大地震影響纪蜒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜寻行,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一霍掺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦杆烁、人聲如沸牙丽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锐墙,卻和暖如春析校,著一層夾襖步出監(jiān)牢的瞬間构罗,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工智玻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吊奢。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓盖彭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親页滚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容