C++中模板類使用友元模板函式
問題始於學習資料結構,自己編寫一個單鏈表,其中用到了過載輸出運算子<<,我寫的大約這樣:
template <class T>
class List
{
friend std::ostream& operator << (std::ostream& os,const List<T>& slist);
//……
};
用vs2008可編譯,但無法連結:無法解析的外部符號
後來上網查改為
template <class T>
class List
{
friend std::ostream& operator << <>(std::ostream& os,const List<T>& slist);
//……
};
就可以了。不知所以然,查了下《C++ Primer》才弄明白。
好了,進入正題:
在類模板中可以出現三種友元宣告:
(1)普通非模板類或函式的友元宣告,將友元關係授予明確指定的類或函式。
(2)類模板或函式模板的友元宣告,授予對友元所有例項的訪問權。
(3)只授予對類模板或函式模板的特定例項的訪問權的友元宣告。
要注意的是,友元函式並非成員函式,是改變了它對類成員的訪問許可權。
(1)沒有什麼好說的,如:
template<class T>
class A
{
friend void fun();
//...
};
此例中fun可訪問A任意類例項中的私有和保護成員
(2)
template<class T>
class A
{
template<class T>
friend void fun(T u);
//...
};
這時友元使用與類不同的模板形參,T可以是任意合法標誌符,友元函式可以訪問A類的任何類例項的資料,即不論A的形參是int,double或其他都可以。
(3)
template<class T>
class A
{
friend void fun<T >(T u);
//...
};
此時fun只有訪問類中特定例項的資料。換句話說,此時具有相同模板實參的fun函式與A類才是友元關係。即假如呼叫fun時其模板實參為int,則它只具有A的訪問許可權。當然friend void fun(T u);中<>中的T可以是任意型別,比如int,double等
回到原問題,按(3)可改為:
template <class T>
class List
{
friend std::ostream& operator << <T>(std::ostream& os,const List<T>& slist);
//……
};
按(2)可改為:
template <class T>
class List
{
template <class T>
friend std::ostream& operator << (std::ostream& os,const List<T>& slist);
//……
};
在這裡其實兩者實現的最終效果一樣的,因為呼叫輸出運算子時需要訪問的類例項的物件是它本身,所以形參T在第一種改法中一定匹配。
對類建立友元函式很容易。但是遷移到模板上卻容易出現讓人摸不著頭腦的連線錯誤。
層次不夠,不做分析,單純介紹兩種為類模板定義友元函式的方法
1 封閉型
template< typename T >
class MyClass
{
friend void function( MyClass< T > &arg )
{
....
}
};
要點:友元函式定義在模板體內。
2 開放型
template< typename T >
class MyClass
{
template< typename C >
friend void function( MyClass< C > &arg );
};
template< typename C >
void function( MyClass< C > &arg )
{
....
}
要點:模板體內要另建模板。
3 告訴編譯器宣告的設個是模板
#include <iostream>
using namespace std;
template < typename T >
class A
{
friend ostream &operator<< < T >( ostream &, const A< T > & );
};
template < typename T >
ostream &operator<< ( ostream &output, const A< T > &a )
{
output << "過載成功" << endl;
return output;
}
int main()
{
A< int > a;
cout << a;
}
要點:顯示地在過載的運算子或者函式後面加上模板宣告< T >,告訴編譯器友元函式是一個型別一致的模板。
建議:
如果希望使用函式與模板特化的型別相對應,則使用方法3(模板顯示宣告)
如果希望使用函式與模板特化的型別相獨立,則使用方法2(二重模板)
簡短的行內函數使用方法1