類的作用域
每個類都會定義其自身的作用域。在該作用域之外课幕,普通的數(shù)據(jù)和函數(shù)成員只能通過對象、引用和指針、成員訪問運算符進(jìn)行訪問。對于類類型的成員則需要使用作用域運算符進(jìn)行訪問。不論何種情況,跟在運算符之后的名字都必須是對應(yīng)類的成員煎谍。
作用域和定義在類外部的成員
一個類就是一個作用域,因此在類外定義成員函數(shù)需要同時提供類名和函數(shù)名龙屉。在類外部呐粘,成員名字被隱藏起來了。
另一方面转捕,函數(shù)返回類型通常出現(xiàn)在函數(shù)名之前作岖。因此當(dāng)成員函數(shù)定義在類外時,返回類型中使用的名字都位于類的作用域之外五芝。此時返回類型必須指明它是哪個類的成員痘儡,且如果在類內(nèi)使用了using或者typedef等語句,則這些名字也有自己的作用域枢步。如:
class A {
public:
using v = std::vector<int>::size_type;
v foo();
};
A::v A::foo() {
return 1;
}
名字查找與類的作用域
名字查找name lookup的過程:
- 首先在名字所在的塊中尋找聲明沉删,只考慮使用之前出現(xiàn)的聲明;
- 沒找到則向外一層繼續(xù)向上找醉途;
- 最終沒找到則報錯矾瑰。
對于類內(nèi)部的成員函數(shù),解析名字的方式與上述不同结蟋,是一個兩階段的處理:
- 首先編譯類內(nèi)成員的聲明脯倚;
- 直到類全部可見渔彰,編譯函數(shù)體嵌屎。
這種兩階段方式處理類可以簡化代碼組織推正。成員函數(shù)體直到整個類可見后才會進(jìn)行處理,因此函數(shù)體可使用類內(nèi)定義的任何一個名字宝惰。
類成員聲明的名字查找
兩階段方式僅適用于成員函數(shù)植榕。對于返回類型、聲明尼夺、參數(shù)列表中的名字尊残,都必須在使用前確保可見淤堵。若出現(xiàn)了類中尚未出現(xiàn)的名字寝衫,則編譯器會在定義該類的外層作用域繼續(xù)查找。
類型名特殊處理
內(nèi)層作用域可以重新定義外層作用域的名字拐邪,即使該名字已經(jīng)在內(nèi)層使用過慰毅。但在類中,如果成員使用了外層作用域的某個名字而該名字代表一種類型扎阶,則該類不能在之后重新定義該名字汹胃。
經(jīng)測試,MS VC++ 14.0 _MSC_VER = 1900
版本中已經(jīng)可行东臀!
typedef unsigned long M;
class A {
public:
M fa() {return -1;}
using M = long;
typedef long M;
M fb() {return -1;}
};
int main(){
A a;
std::cout<<a.fa() //4294967295
<<'\n'<<a.fb(); //-1
}
成員定義中的普通塊作用域的名字查找
- 成員函數(shù)塊內(nèi)向上
- 類內(nèi)所有成員
- 外部:成員函數(shù)定義之前
在成員函數(shù)內(nèi)使用與形參列表中同名的類內(nèi)成員:
兩種實現(xiàn)方式分別為:this->xx
和 A::XX
着饥,但是建議最好為形參起一個不會重名的名字。
在類作用域之后惰赋,在外圍作用域查找
編譯器在函數(shù)和類的作用域都找不到名字則繼續(xù)在外圍作用域查找宰掉。此外,可以顯式使用作用域運算符對外層作用域進(jìn)行請求:::xx
赁濒,符號前無任何內(nèi)容贵扰。
在文件中名字出現(xiàn)處對其進(jìn)行解析
當(dāng)成員定義在類的外部時,名字查找的第三步不僅要考慮定義之前的全局作用域中的聲明流部,還要考慮在成員函數(shù)定義之前的全局作用域的聲明戚绕。