友元函數在類中的聲明在外圍是不可見的,聲明
上圖所示在外圍的C類中聲明了兩個友元函數,f()和f(C<T> const&)
但是在main()函數中使用時,f()被提示沒有找到該函數的聲明, 但是f(*p)卻找到了函數的聲明
這是因為:
第一,C++標准規定友元聲明在類中,外圍作用域是不可見的
第二,C++可以根據ADL查找規則找到該函數的聲明
比如上面的f(*p)的形式參數是C<int> 那麼ADL查找的關聯集合就會包含
模板C實例化後的C<int>作用域,也就能夠找到函數f(C<int> const&);的聲明
好,那麼問題來了,為什麼f()函數不能根據ADL查找到聲明,f(*p)就可以?
仔細觀察這兩個函數,就會發現f()沒有參數,但是f(*p)有參數。
ADL查找規則
ADL 全稱
Argument-Dependent Lookup
第一,使用此規則的函數必須要有參數
第二,使用此規則的函數名稱必須為非受限名稱,即名稱前面沒有顯式的出現 ->, ::, . 這三個限定符
如何查找
如果函數名稱後面有一個或多個實參表達式,那麼ADL將會查找這些實參的
關聯類 和
關聯名字空間
對於給定的類型,
關聯類 和
關聯名字空間 所組成的集合的准確定義可以通過下列規則來確定:
(1)對於基本類型(int, char等), 該集合為空集
(2)對於指針和數組類型,該集合是所引用類型的關聯類和關聯名字空間
(3)對於枚舉類型,名字空間是名字空間是枚舉聲明所在的名字空間,對於類成員,關聯類是枚舉所在的類
(4)對於class(包含聯合類型),關聯類包括該類本身,他的外圍類,直接基類,間接基類。關聯名字空間包括每個關聯類所在的名字空間。
(5)對於函數類型, 該集合包含所有參數類型和返回類型的關聯類和關聯名字空間
(6)對於類X的成員指針類型,除了包括成員相關的關聯名字空間,關聯類,該集合還包括與X相關的關聯名字空間和關聯類
此外ADL查找會忽略using關鍵字的名字空間。
自此,ADL會在所有的關聯類 和 關聯名字空間 依次查找直到找到符合的聲明。
當一個類聲明友元函數的時,函數的聲明不必是可見的這是什
說起來比較復雜,並且跟friend沒什麼關系
namespace A{ class C{}; void f(const C&); void f1(int);}int f2(){ f1(42);//因為沒有using A::f1,這樣的調用不會成功 A::C obj; f(obj);//但是因為obj的類型與命名空間A相關,這樣是可以成功編譯的}
友元函數只可以在類中聲明定義
友元函數必須在類中聲明,至於定義的函數體,你液可以寫到類外面去!布過不用再寫friend,只在聲明中寫friend即可!