最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++類成員函數(shù)中的名字查找問題

 更新時(shí)間:2022年11月24日 14:10:20   作者:棉猴  
這篇文章主要介紹了C++類成員函數(shù)中的名字查找問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

C++類成員函數(shù)中的名字查找

在C++類的成員函數(shù)中,名字查找是按照由內(nèi)到外進(jìn)行的。首先查找成員函數(shù)中的名字,之后再查找類中定義的名字,最后查找類外定義的名字。

查找順序

自定義類MyClass代碼如下

int i = 1;
class MyClass {
? public:
? ? int i = 2;
? ? void myFunc() {
? ? ? int i = 3;
? ? ? int j = i;
? ?}
};

其中,在MyClass類的成員函數(shù)myFunc()中使用了變量i,而在myFunc()函數(shù)、MyClass類以及類外都定義了變量i,此時(shí)myFunc()成員函數(shù)會(huì)根據(jù)由內(nèi)向外的順序?qū)進(jìn)行查找,即此時(shí)j的值應(yīng)該是3。

使用指定的名字

使用類的變量

在myFunc()中如果需要使用類myFunc()函數(shù)的變量i,可以進(jìn)行如下定義

int j = MyClass::i;

或者

int j = this->i;

此時(shí),表示使用MyClass中定義的變量i,j的值是2。

使用類外變量

在myFunc()中如果需要使用類外定義的變量i,可以進(jìn)行如下定義

int j = ::i;

此時(shí),j的值是1。

C++名字查找與類的作用域

每個(gè)類都會(huì)定義它自己的作用域。在類的作用域之外,普通的數(shù)據(jù)和函數(shù)成員只能由對(duì)象、引用或者指針使用成員訪問運(yùn)算符來訪問。對(duì)于類類型成員則使用作用域運(yùn)算符訪問。不論哪種情況,跟在運(yùn)算符之后的名字都必須是對(duì)應(yīng)類的成員。

Screen::pos ht = 24, wd = 80; ?// 使用 Screen 定義的 pos 類型
Screen scr(ht, wd, ' ');
Screen *p = &scr;
char c = scr.get(); ?// 訪問 scr 對(duì)象的 get 成員
c = p->get(); ?// 訪問 p 所指對(duì)象的 get 成員

作用域和定義在類外部的成員

類的作用域 (class scope) 每個(gè)類定義一個(gè)作用域。類作用域比其他作用域更加復(fù)雜,類中定義的成員函數(shù)甚至有可能使用定義語句之后的名字。

一個(gè)類就是一個(gè)作用域,我們?cè)陬惖耐獠慷x成員函數(shù)時(shí)必須同時(shí)提供類名和函數(shù)名。在類的外部,成員的名字被隱藏起來了。一旦遇到了類名,定義的剩余部分就在類的作用域之內(nèi)了,這里的剩余部分包括參數(shù)列表和函數(shù)體。結(jié)果就是,我們可以直接使用類的其他成員而無須再次授權(quán)了。

void Window::clear(ScreenIndex i)
{
?? ?Screen &s = screens[i];
?? ?s.contents = string(s.height * s.width, ' ');
}

編譯器在處理參數(shù)列表之前已經(jīng)明確了我們當(dāng)前正位于 Window 類的作用域中,所以不必再專門說明 ScreenIndex 是 Window 類定義的。出于同樣的原因,編譯器也能知道函數(shù)體中用到的 screens 也是在 Window 類中定義的。

函數(shù)的返回類型通常出現(xiàn)在函數(shù)名之前。因此當(dāng)成員函數(shù)定義在類的外部時(shí),返回類型中使用的名字都位于類的作用域之外。這時(shí),返回類型必須指明它是哪個(gè)類的成員。我們可能向 Window 類添加一個(gè)新的名為 add_screen 的函數(shù),它負(fù)責(zé)向顯示器添加一個(gè)新的屏幕。這個(gè)成員的返回類型將是 ScreenIndex,用戶可以通過它定位到指定的 Screen。

class Window {
public:
?? ?// 向窗口添加一個(gè) Screen,返回它的編號(hào)
?? ?ScreenIndex add_screen(const Screen &);
?? ?......
};

// 首先處理返回類型,之后我們才進(jìn)入 Window 的作用域
Window::ScreenIndex
Window::add_screen(const Screen &s)
{
?? ?screens.push_back(s);
?? ?return screens.size() - 1;
}

因?yàn)榉祷仡愋统霈F(xiàn)在類名之前,所以事實(shí)上它是位于 Window 類的作用域之外的。在這種情況下,要想使用 Screenlndex 作為返回類型,我們必須明確指定哪個(gè)類定義了它。

名字查找與類的作用域

名字查找 (name lookup) (尋找與所用名字最匹配的聲明的過程) 的過程比較直截了當(dāng)。

  • 首先,在名字所在的塊中尋找其聲明語句,只考慮在名字的使用之前出現(xiàn)的聲明。
  • 如果沒找到,繼續(xù)查找外層作用域。
  • 如果最終沒有找到匹配的聲明,則程序報(bào)錯(cuò)。

對(duì)于定義在類內(nèi)部的成員函數(shù)來說,解析其中名字的方式與上述的查找規(guī)則有所區(qū)別,不過在當(dāng)前的這個(gè)例子中體現(xiàn)得不太明顯。

類的定義分兩步處理:

  • 首先,編譯成員的聲明。
  • 直到類全部可見后才編譯函數(shù)體。

編譯器處理完類中的全部聲明后才會(huì)處理成員函數(shù)的定義。按照這種兩階段的方式處理類可以簡(jiǎn)化類代碼的組織方式。因?yàn)槌蓡T函數(shù)體直到整個(gè)類可見后才會(huì)被處理,所以它能使用類中定義的任何名字。

名字查找 (name lookup) 是根據(jù)名字的使用尋找匹配的聲明的過程。

用于類成員聲明的名字查找

這種兩階段的處理方式只適用于成員函數(shù)中使用的名字。聲明中使用的名字,包括返回類型或者參數(shù)列表中使用的名字,都必須在使用前確??梢姟H绻硞€(gè)成員的聲明使用了類中尚未出現(xiàn)的名字,則編譯器將會(huì)在定義該類的作用域中繼續(xù)査找。

typedef double Money;
std::string bal;

class Account {
public:
?? ?Money balance() { return bal; }

private:
?? ?Money bal;

};

當(dāng)編譯器看到 balance 函數(shù)的聲明語句時(shí),它將在 Account 類的范圍內(nèi)尋找對(duì) Money 的聲明。編譯器只考慮 Account 中在使用 Money 前出現(xiàn)的聲明,因?yàn)闆]找到匹配的成員,所以編譯器會(huì)接著到 Account 的外層作用域中查找。在這個(gè)例子中,編譯器會(huì)找到 Money 的 typedef 語句,該類型被用作 balance 函數(shù)的返回類型以及數(shù)據(jù)成員 bal 的類型。balance 函數(shù)體在整個(gè)類可見后才被處理,該函數(shù)的 return 語句返回名為 bal 的成員,而非外層作用域的 std::string 對(duì)象。

類型名要特殊處理

內(nèi)層作用域可以重新定義外層作用域中的名字,即使該名字已經(jīng)在內(nèi)層作用域中使用過。然而在類中,如果成員使用了外層作用域中的某個(gè)名字,而該名字代表一種類型,則類不能在之后重新定義該名字。

typedef double Money;

class Account {
public:
?? ?Money balance() { return bal; } ?// 使用外層作用域的 Money

private:
?? ?typedef double Money; ?// 錯(cuò)誤:不能重新定義 Money
?? ?Money bal;
};

需要特別注意的是,即使 Account 中定義的 Money 類型與外層作用域一致,上述代碼仍然是錯(cuò)誤的。盡管重新定義類型名字是一種錯(cuò)誤的行為,但是編譯器并不為此負(fù)責(zé)。一些編譯器仍將順利通過這樣的代碼,而忽略代碼有錯(cuò)的事實(shí)。類型名的定義通常出現(xiàn)在類的開始處,這樣就能確保所有使用該類型的成員都出現(xiàn)在類名的定義之后。

成員定義中的普通塊作用域的名字查找

成員函數(shù)中使用的名字按照如下方式解析:

  • 首先,在成員函數(shù)內(nèi)查找該名字的聲明。和前面一樣,只有在函數(shù)使用之前岀現(xiàn)的 聲明才被考慮。
  • 如果在成員函數(shù)內(nèi)沒有找到,則在類內(nèi)繼續(xù)査找,這時(shí)類的所有成員都可以被考慮。
  • 如果類內(nèi)也沒找到該名字的聲明,在成員函數(shù)定義之前的作用域內(nèi)繼續(xù)查找。

一般來說,不建議使用其他成員的名字作為某個(gè)成員函數(shù)的參數(shù)。為了更好地解釋名字的解析過程,我們不妨在 dummy_fcn 函數(shù)中暫時(shí)違反一下這個(gè)約定。

// 這段代碼僅為了說明而用,不是一段很好的代碼
// 通常情況下不建議為參數(shù)和成員使用同樣的名字

int height; ?// 定義了一個(gè)名字,稍后將在 Screen 中使用

class Screen {
public:
?? ?typedef std::string::size_type pos;
?? ?void dummy_fcn(pos height) {
?? ??? ?cursor = width * height; // height 是那個(gè)參數(shù)
?? ?}

private:
?? ?pos cursor = 0;
?? ?pos height = 0, width = 0;
};

當(dāng)編譯器處理 dummy_fcn 中的乘法表達(dá)式時(shí),它首先在函數(shù)作用域內(nèi)查找表達(dá)式中用到的名字。函數(shù)的參數(shù)位于函數(shù)作用域內(nèi),因此 dummy_fcn 函數(shù)體內(nèi)用到的名字 height 指的是參數(shù)聲明。在此例中,height 參數(shù)隱藏了同名的成員。如果想繞開上面的查找規(guī)則,應(yīng)該將代碼變?yōu)椋?/p>

// 不建議的寫法:成員函數(shù)中的名字不應(yīng)該隱藏同名的成員
void Screen::dummy_fcn(pos height) {
?? ?cursor = width * this->height; ?// 成員 height
?? ?// 另外一種表示該成員的方式
?? ?cursor = width * Screen::height; ?// 成員 height
}

盡管類的成員被隱藏了,但我們?nèi)匀豢梢酝ㄟ^加上類的名字或顯式地使用 this 指針來強(qiáng)制訪問成員,其實(shí)最好的確保我們使用 height 成員的方法是給參數(shù)起個(gè)其他名字。

// 建議的寫法:不要把成員名字作為參數(shù)或其他局部變量使用
void Screen::dummy_fcn(pos ht) {
?? ?cursor = width * height; ?// 成員 height
}

在此例中,當(dāng)編譯器查找名字 height 時(shí),顯然在 dummy_fcn 函數(shù)內(nèi)部是找不到的。編譯器接著會(huì)在 Screen 內(nèi)查找匹配的聲明,即使 height 的聲明出現(xiàn)在 dummy_fcn 使用它之后,編譯器也能正確地解析函數(shù)使用的是名為 height 的成員。

類作用域之后,在外圍的作用域中查找

如果編譯器在函數(shù)和類的作用域中都沒有找到名字,它將接著在外圍的作用域中查找。在我們的例子中,名字 height 定義在外層作用域中,且位于 Screen 的定義之前。 然而,外層作用域中的對(duì)象被名為 height 的成員隱藏掉了。如果我們需要的是外層作用域中的名字,可以顯式地通過作用域運(yùn)算符來進(jìn)行請(qǐng)求。

// 不建議的寫法:不要隱藏外層作用域中可能被用到的名字
void Screen::dummy_fcn(pos height) {
?? ?cursor = width * ::height; ?// height 是哪個(gè)全局的
}

盡管外層的對(duì)象被隱藏掉了,但我們?nèi)匀豢梢杂米饔糜蜻\(yùn)算符訪問它。

在文件中名字的出現(xiàn)處對(duì)其進(jìn)行解析

當(dāng)成員定義在類的外部時(shí),名字査找的第三步不僅要考慮類定義之前的全局作用域中的聲明,還需要考慮在成員函數(shù)定義之前的全局作用域中的聲明。

int height; ?// 定義了一個(gè)名字,稍后將在 Screen 中使用

class Screen {
public:
?? ?typedef std::string::size_type pos;
?? ?void setHeight(pos);
?? ?pos height = 0; ?// 隱藏了外層作用域中的 height
};

Screen::pos verify(Screen::pos);

void Screen::setHeight(pos var) {
?? ?// var: 參數(shù)
?? ?// height: 類的成員
?? ?// verify: 全局函數(shù)
?? ?height = verify(var);
}

全局函數(shù) verify 的聲明在 Screen 類的定義之前是不可見的。名字査找的第三步包括了成員函數(shù)出現(xiàn)之前的全局作用域。在此例中,verify 的聲明位于 setHeight 的定義之前,因此可以被正常使用。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C語言中字符串常用函數(shù)strcat與strcpy的用法介紹

    C語言中字符串常用函數(shù)strcat與strcpy的用法介紹

    以下是對(duì)C語言中字符串常用函數(shù)strcat與strcpy的使用方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下
    2013-07-07
  • c語言中的局部跳轉(zhuǎn)及全局跳轉(zhuǎn)功能

    c語言中的局部跳轉(zhuǎn)及全局跳轉(zhuǎn)功能

    本文介紹了C語言中的goto語句,以及如何使用setjmp和longjmp實(shí)現(xiàn)跨函數(shù)的跳轉(zhuǎn),詳細(xì)講解了setjmp和longjmp的使用方法和注意事項(xiàng),以及使用這種全局跳轉(zhuǎn)后變量狀態(tài)的不確定性,感興趣的朋友一起看看吧
    2024-09-09
  • 你必須知道的C語言預(yù)處理的問題詳解

    你必須知道的C語言預(yù)處理的問題詳解

    本篇文章介紹了,你必須知道的C語言預(yù)處理的問題。需要的朋友參考下
    2013-05-05
  • C++?RBTree紅黑樹的性質(zhì)與實(shí)現(xiàn)

    C++?RBTree紅黑樹的性質(zhì)與實(shí)現(xiàn)

    紅黑樹是一種二叉搜索樹,但在每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色,可以是Red或Black;通過對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制,紅黑樹確保沒有一條路徑會(huì)比其他路徑長(zhǎng)出倆倍,因而是平衡的
    2023-03-03
  • QT實(shí)現(xiàn)QML側(cè)邊導(dǎo)航欄的最簡(jiǎn)方法

    QT實(shí)現(xiàn)QML側(cè)邊導(dǎo)航欄的最簡(jiǎn)方法

    本文主要介紹了QT實(shí)現(xiàn)QML側(cè)邊導(dǎo)航欄的最簡(jiǎn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放的方法

    C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放的方法

    當(dāng)我們開發(fā)Windows應(yīng)用程序時(shí),通常會(huì)涉及到使用資源(Resource)的情況。資源可以包括圖標(biāo)、位圖、字符串等,它們以二進(jìn)制形式嵌入到可執(zhí)行文件中,這篇文章主要介紹了C/C++?實(shí)現(xiàn)動(dòng)態(tài)資源文件釋放,需要的朋友可以參考下
    2023-12-12
  • 二分圖匹配實(shí)例代碼及整理

    二分圖匹配實(shí)例代碼及整理

    這篇文章主要介紹了二分圖匹配實(shí)例代碼及整理的相關(guān)資料,這里提供了三種方法包括匈牙利算法,KM算法,多重匹配,需要的朋友可以參考下
    2017-07-07
  • C++11系列學(xué)習(xí)之列表初始化

    C++11系列學(xué)習(xí)之列表初始化

    這篇文章主要介紹了C++11系列學(xué)習(xí)之列表初始化,標(biāo)準(zhǔn)初始化方式太過繁雜,限制偏多,因此在新標(biāo)準(zhǔn)中統(tǒng)一了初始化方,為了讓初始化具有確定的效果,于是提出了列表初始化概念,下文我們就一起來學(xué)習(xí)該詳細(xì)內(nèi)容介紹吧
    2022-04-04
  • c++編寫String類代碼實(shí)例

    c++編寫String類代碼實(shí)例

    這篇文章主要介紹了c++編寫String類,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • C語言基礎(chǔ) 原碼、反碼、補(bǔ)碼和移碼詳解

    C語言基礎(chǔ) 原碼、反碼、補(bǔ)碼和移碼詳解

    這篇文章主要介紹了C語言基礎(chǔ) 原碼、反碼、補(bǔ)碼和移碼詳解的相關(guān)資料,需要的朋友可以參考下
    2017-01-01

最新評(píng)論

镇江市| 阜宁县| 垦利县| 酉阳| 景德镇市| 阜康市| 双牌县| 武冈市| 永靖县| 个旧市| 遂宁市| 维西| 内江市| 富平县| 东明县| 当涂县| 桂东县| 东宁县| 九江县| 郸城县| 邹城市| 三原县| 左权县| 芒康县| 买车| 湖口县| 大渡口区| 密山市| 锦屏县| 泰顺县| 鄢陵县| 昭通市| 萍乡市| 纳雍县| 合水县| 潮安县| 师宗县| 徐水县| 邵阳县| 临高县| 新民市|