1. 程式人生 > >C++模板類中的友元宣告

C++模板類中的友元宣告

對於在一個類中宣告一個函式或者一個類的友元,我們應該是十分熟悉了,但是這兩天在做題的時候遇到一個問題,就是如何在一個類模板中宣告一個模板函式與我們的模板類的友元關係?

剛開始遇到這個問題的時候,說實話我有點懵,因為之前根本沒考慮到這一層,所以趁這次機會又將模板和友元相關的東西整理了一下,翻了下《C++Primer》,上網查了一下,我大致總結出如下:

模板類中可以出現的三種友元宣告:

1.普通非模板類或函式的友元宣告,將友元關係授予明確指定的類或函式;

2.類模板或函式模板的友元宣告,授予對應的類模板或函式模板所有例項對我們的模板類所有例項中的所有成員的訪問權;

3.只授予類模板或函式模板的特定例項對我們的模板類所有例項或對應例項中的所有成員的訪問權的友元宣告;

上面三點或許有點繞,下面來逐點解釋:(以下均用函式模板的友元宣告來舉例,類模板的友元宣告與之類似)

1.其實第一點挺簡單的,沒有什麼好說的,例子如下:

template<class T>
class A
{
	friend void fun();
	friend class B;

private:
	T _a;
};
void fun()
{
	A<int> a1;
	A<double> a2;
	a1._a=1;
	a2._a=1.0;
	cout<<a1._a<<endl;
	cout<<a2._a<<endl;
}
這個例子中,可以在fun函式中訪問A任意例項中的私有或保護成員;


2.在模板類內宣告友元的函式模板

template<typename T>
class A
{
	template<class T1>
	friend void fun();
private:
	T _a;
};

template<typename T1>
void fun()
{
	A<int> a1;
	A<double> a2;
	a1._a=1;
	a2._a=1.0;

	cout<<a1._a<<endl;
	cout<<a2._a<<endl;
}

void funtest()
{
	fun<int>();
	fun<double>();
}
就如上面這個例子,在我們模板類A中聲明瞭模板函式fun,兩者擁有各自的模板形參T和T1,兩者是互不影響的,所以在這裡對於fun的所有例項(如fun<int>,fun<double>)對於A的所有例項(如A<int>,A<double>)中的私有或保護成員都可以進行訪問;


3.在模板類中宣告模板函式的某一特定例項的友元關係
template<class T1>
void fun();

template<typename T>
class A
{
	friend void fun<int>();
private:
	T _a;
};

template<typename T1>
void fun()
{
	A<int> a1;
	A<double> a2;
	a1._a=1;
	a2._a=1.0;
	cout<<a1._a<<endl;
	cout<<a2._a<<endl;
}
void funtest()
{
	fun<int>();
	//fun<double>();
}

int main()
{
	funtest();
	return 0;
}

上面這個例子,在模板類A中我們聲明瞭模板函式fun例項化後的fun<int>的友元關係,因此我們在這裡僅能夠在fun<int>中對模板類A中的所有例項的私有或保護成員具有訪問許可權,而對於fun<double>則不是模板類A的友元函式,不具有訪問其例項的私有或保護成員的許可權(編譯會出錯)。

對於上面這個例子,我們可以做一點改動,將友元宣告改為friend void fun<T>();
template<class T1>
void fun();

template<typename T>
class A
{
	friend void fun<T>();
private:
	T _a;
};

template<typename T1>
void fun()
{
	A<int> a1;
	A<double> a2;
	a1._a=1;
	a2._a=1.0;
	cout<<a1._a<<endl;
	cout<<a2._a<<endl;
}
void funtest()
{
	fun<int>();
	fun<double>();
}

int main()
{
	funtest();
	return 0;
}

將上面的例子拿去測試,我們發現對於fun<int>僅對模板類A的例項A<int>的私有或保護成員具有訪問許可權,對於A<double>則沒有;而對於fun<double>則反之。總之,對於fun的例項只對與它的模板實參一致的A例項有友元關係。

這裡需要注意一點,對於第三種友元,要對我們的函式模板進行前置宣告(雖然在某些情況下,不加前置宣告也不會報錯)。

到這裡應該大致明白類模板中可以進行的三種友元的聲明瞭,對於第一種友元的宣告,真的挺簡單的,沒有什麼好說的,下面著重來討論對於建立友元的函式的模板該如何進行定義宣告。
1.封閉型
也就是將我們的函式模板的定義和友元宣告均放在我們的類模板中,而因為在類內定義所以就會被看做行內函數,在所有成員函式定義之後被定義。
例如:
template<typename T>
class A
{
public:
	A()
		:_a(0)
	{}

	template<class T1>
	friend void fun(const A<T1> a)
	{
		cout<<a._a<<endl;
	}

private:
	T _a;
};

但是想上述的第三種情況就不適用於這種方法了。
2.開放型
我們前面介紹三類友元的宣告中的例子就是我們的開放型,也就是將函式模板的定義放在我們的類模板外。

參考連結:http://www.cppblog.com/unixfy/archive/2011/05/27/147448.html
                    http://blog.sina.com.cn/s/blog_7c2c21230100svc3.html