C++ 名稱查找是透過名稱找到對應宣告的過程。對於函數,可能匹配多個宣稱,再經過 Argument-dependent Lookup、Template Argument Deduction、Overload Resolution 解析。名稱查找分為 Qualified(帶 ::)與 Unqualified(不帶 ::)兩類。
Qualified name 出現在 :: 右側,可為類成員、命名空間成員、枚舉等。
:: 左側無元素時預設為全域命名空間:
struct std {};
std::cout << "fail"; // 錯誤:unqualified lookup 找到 struct std
::std::cout << "ok"; // 正確:::std 找到命名空間 std
:: 左側元素只能是命名空間、類、枚舉、模板。
class X {};
constexpr int number = 100;
class C {
class X {};
static const int number = 50;
static X arr[number];
};
X C::arr[number], brr[number]; // 錯誤:arr 後的 number 在 C:: 中查找
C::X C::arr[number], brr[number]; // 正確
若 :: 右側為解構函數,其名稱查找與左側一致:
struct C { typedef int I; };
typedef int I1, I2;
struct A { ~A(){}; };
typedef A AB;
int main() {
p->C::I::~I(); // ~ 後的 I 在 C 中查找
q->I1::~I2(); // I2 在當前作用域查找
AB x; x.AB::~AB(); // AB 在當前作用域查找
}
:: 兩側同為類名時視為建構函數;使用 elaborated type specifier(如 struct A::A)則忽略函數,視為類型:
struct A { A(); };
struct B : A { B(); };
A::A() {} // 建構函數
B::B() {} // 建構函數
B::A ba; // 類型 A
A::A a; // 錯誤
struct A::A a2; // 正確:elaborated type specifier 忽略函數
Qualified name 可存取被嵌套或繼承隱藏的成員:
struct B { virtual void foo(); };
struct D : B { void foo() override; };
int main() {
D x; B& b = x;
b.foo(); // 動態分派呼叫 D::foo
b.B::foo(); // 靜態分派呼叫 B::foo
}
命名空間中 qualified name 遞歸查找,允許同一實體經由不同路徑被找到:
namespace A { int a; }
namespace B { using namespace A; }
namespace D { using A::a; }
namespace BD { using namespace B; using namespace D; }
void g() { BD::a++; } // OK:經由 B 和 D 找到同一 A::a
Qualified name lookup 規則嚴謹,理解其作用域遞歸、隱藏成員存取、elaborated type specifier 等細節,對編寫正確、可維護的 C++ 程式碼至關重要。