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

C++中模板類的友元過載

一個由《程式設計師面試寶典》引出的問題。

描述模板類的友元過載,用C++程式碼實現?

這實際上考察的是下面幾個問題:

1.模板類的編寫

2.模板類中友元函式的編寫

3.什麼時候會用到友元過載?答案是各種C++中的運算子。最典型的就是輸出操作符<<了。

書上給出的答案如下:

#include <iostream>

using namespace std;

template<class T> class Test;

template<class T> ostream & operator<<(ostream & out,const Test<T> &obj);

template<class T> class Test{

	private:
		int num;
	public:
		Test(int n=0){num=n;}

		Test(const Test <T> &copy){num=copy.num;}

		//注意在“<<”後加上“<>”表示這是一個函式模板
		friend ostream& operator<< <> (ostream & out,const Test<T> &obj);
};	

template<class T> ostream& operator<<(ostream & out,const Test<T> &obj){
	out<<obj.num;
	return out;
}

int main(){
	Test<int> t(2);
	cout<<t;
	return 0;
}

只是對上面註釋的哪一行不是很理解於是翻了下《C++ Primer》,發現書上對這個問題講的很詳細了。複製過來:

類模板中的友元宣告

在類模板中可以出現三種友元宣告,每一種都聲明瞭與一個或多個實體的友元關係:

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

(2)類模板或函式模板的友元宣告,授予對有緣所有例項的訪問權

(2)只授予對類模板或函式模板的特定例項的訪問權的友元宣告

1.普通友元

非模板類或非模板函式可以是類模板的友元:

template<class Type> class Bar{
	//授權給普通類和或函式
	friend class FolBar;
	friend void fcn();
};
這個宣告是說,FolBar的成員和fcn函式可以訪問Bar類的任何例項的privete成員和protected成員。

2.一般模板友元

友元可以是類模板或函式模板:

template<class Type> class Bar{
	//授權給Foo1或temp1_fcn1的任何例項
	template<class T> friend class Foo1;
	template<class T> friend void temp1_fcn1(const T&);
};

這些友元宣告使用與類本身不同的型別形參,該型別形參指的是Foo1和temp1_fcn1的型別形參。在這兩種情況下,都將沒有數目限制的類和函式設為Bar的友元。Foo1的友元宣告是說,Foo1的任何例項都可以訪問Bar的任何例項的私有成員,類似地,temp1_fcn1的任何例項可以訪問Bar的任意例項。

這個友元宣告在Bar與其友元Foo1和temp1_fcn1的每個例項之間建立了一對多的對映。對Bar的每個例項而言,Foo1或temp1_fcn1的所有例項都是友元。

3.特定的模板友元關係

除了將一個模板的所有例項設為友元,類也可以只授予對特定例項的訪問權。

template<class T> class Foo2;
	template<class T> void temp1_fcn2(const T&);
	template<class Type> class Bar{
		//只授權給引數型別為char*的例項
		friend class Foo2<char *>;
		friend void temp1_fcn2<char *>(char * const &);
	};
即使Foo2本身是類模板,友元關係也只擴充套件到Foo2的形參型別為char*的特定例項。類似地,temp1_fcn2的友元宣告是說,只有引數型別為char*的函式例項是Bar類的友元。形參型別為char*的Foo2和temp1_fcn2的特定例項可以訪問Bar的每個例項。
下面形式的友元宣告更加常見:
template<class T> class Foo3;
	template<class T> void temp1_fcn3(const T&);
	template<class Type> class Bar{
		//Bar的每一個例項只能訪問引數型別和Bar相同的Foo3和temp1_fcn3的例項
		friend class Foo3<Type>;
		friend void temp1_fcn3<Type>(const Type &);
	};
這些友元定義了Bar的特定例項與使用同一模板實參的Foo3或temp1_fcn3的例項之間的友元關係,每個Bar例項有一個相關的Foo3和temp1_fcn3友元:
	Bar<int> b1;//它的友元是Foo3<int>和temp1_fcn3<int>
	Bar<string> bs;//它的友元是Foo3<string>和temp1_fcn3<string>

只有與給定Bar例項有相同模板實參的那些Foo3或temp1_fcn3版本是友元。因此,Foo3<int>可以訪問Bar<int>的私有部分,但不能訪問Bar<string>或者任意其他Bar例項的私有部分。

4.宣告依賴性

當授予給定模板的所有例項的訪問權的時候,在作用域中不需要存在該類模板或函式模板的宣告。實質上,編譯器將友元宣告也當做類或函式的宣告對待。

想要限制對特定例項化的友元關係時,必須在可以用於友元宣告之前宣告類或函式:

template <class T> class A;
template <class T> class B{
	public:
		friend class A<T>;//ok,A做了宣告
		friend class C;//ok,C是一個普通類
		template<class S> friend class D;//ok,D是一個模板,並且是對D的所有例項授權
		friend class E<T>;//error,需要宣告
		friend class F<int>;//error,需要宣告
};

在g++中會出現這個錯誤:

如果沒有事先告訴編譯器該友元是一個模板,則編譯器將認為該友元是一個普通非模板類或非模板函式。

上面就是《C++ Primer》關於模板類中友元的說明,理解完這些後再來看這道題就很好理解。根據第3點,特定的模板友元關係可以明白為什麼需要<>了,實際上是<T>,不過可以只寫成<>。

根據第4點型別依賴性可以明白為什麼在最上面需要加上聲明瞭。

然後可以按照第2點一般模板友元關係的方式進行改寫,程式碼如下:但是感覺沒有這個必要。

注意,此時前面的宣告不需要了,因為按照上面第4點,對所有例項都訪問權時是不需要事先宣告的。

<<後面也不需要<>了。因為此時前面加上了template<class TT>這個關鍵字。

注意:為了防止以後在類模板或函式模板中漏掉<>這個符號,可以這樣記憶,對於類模板或函式模板,要麼有template<class >修飾,要麼有需要有<>兩者必須有其一

#include <iostream>

using namespace std;

template<class T> class Test{

	private:
		int num;
	public:
		Test(int n=0){num=n;}

		Test(const Test <T> &copy){num=copy.num;}

		//注意在“<<”後加上“<>”表示這是一個函式模板
		template<class TT> friend ostream& operator<< (ostream & out,const Test<TT> &obj);
};	

template<class T> ostream& operator<<(ostream & out,const Test<T> &obj){
	out<<obj.num;
	return out;
}




int main(){
	Test<int> t(2);
	cout<<t;
	return 0;
}


相關推薦

C++模板過載

一個由《程式設計師面試寶典》引出的問題。 描述模板類的友元過載,用C++程式碼實現? 這實際上考察的是下面幾個問題: 1.模板類的編寫 2.模板類中友元函式的編寫 3.什麼時候會用到友元過載?答案是各種C++中的運算子。最典型的就是輸出操作符<<了。 書上給出的

C++模板使用模板函式

問題始於學習資料結構,自己編寫一個單鏈表,其中用到了過載輸出運算子<<,我寫的大約這樣: template <class T> class List { friend std::ostream& operator

模板包含模板和其他函式

發表一點自己對 《C++ Primer 5th》模板那塊的理解, 歡迎指正 一對一友好關係 在類模板與另一個模板(模板類或模板函式)間建立對應例項及其友好關係,為了在類模板中引用另一個類模板或函式的一個特定例項,必須先宣告另一個模板: 方便理解和敘述,將含

C++ 模板模板成員函數在外定義

成員函數 成員 typename 開源 splay 開源代碼 pen color play 因為很多書都沒講到這種情況, 曾經有這個問題但一直沒答案,所以我一直以為模板類的模板成員函數只能在類內定義,直到我在某個開源代碼裏看到原來要加兩個 template<>

關於C++的friend函式的總結

1.友元函式的簡單介紹 1.1為什麼要使用友元函式 在實現類之間資料共享時,減少系統開銷,提高效率。如果類A中的函式要訪問類B中的成員(例如:智慧指標類的實現),那麼類A中該函式要是類B的友元函式。 具體來說:為了使其他類的成員函式直接訪問該類的私有變數。即:允許外面的類或函式去訪問

c++模板的使用

最近在資料結構的課程中很多周圍的同學對模板類的使用抱有很大的困惑,看也能看懂,但寫起來總是不明白…… 那就首先得知道為什麼要用模板。 假設我有一個方法 void swap(int& a,int& b) { int c = a;

C++模板map常用示例

#include <iostream> #include <map> using namespace std; int main() { /****************************************************

C++模板宣告和實現能否分離?

1.宣告部分 //point.h #ifndef _POINT_ #define _POINT_ template<class Elem> class Point { public: Point(Elem); } ; #endif 2.實現部分

C++定義一個不能被繼承的(+模板)

自從C++11標準出來之後,就有了關鍵字final可以直接宣告一個類不能被繼承。那麼,在此之前如果想要一個類不能被繼承,可能還需要下一番功夫。 文章目錄 1.宣告建構函式為私有 2.子類宣告為基類的友元類 3.虛繼承——子類

模板使用函式的方式,派生函式對基的成員使用情況

在一般友元函式的前面加上 template<typename T),注意在函式的宣告和定義處都要加這個模板 例如: //模板類,長方體類 template <typename ElementType> class Rectangle { ///*過載基類的輸入輸出運算子*/

C++模板詳細講述

技術 要求 ebe div spa 限制 dcb 模板的模板 文本文件 一、類模板定義及實例化 1. 定義一個類模板: 1 template<class 模板參數表>2 3 class 類名{4 5 // 類定義......6 7 };

c++模板的實現(模板模板函數)

c++ 模板實例化 泛型編程 [TOC] 模板  當我們實現一個交換函數時,我們可以寫成如下。 void Swap(int& x, int& y) { int tmp = x; x = y; y = tmp; }  這裏只能交換兩個整

4、【C++】靜態成員變數/靜態成員函式/行內函數/函式//成員函式

一、靜態成員     我們可以使用 static 關鍵字來把類成員定義為靜態的。當我們宣告類的成員為靜態時,這意味著無論建立多少個類的物件,靜態成員都只有一個副本。     靜態成員在類的所有物件中是共享的。如果不存在其他的初始化語句,在建立第一個物件時,所有的靜態資料都會被初始化為

過載運算子(時間

#include using namespace std; class Time { private: int hour; int minute; int second; public: Time(int a=0,int b=0,int c=0) { this->hour=a; th

C ++字串運算子過載示例

一、基本概念 (一) 函式過載的含義 所謂過載,就是重新賦予新的含義。函式過載就是對一個已有的函式賦予新的含義,使之實現新功能,因此,一個函式名就可以用來代表不同功能的函式,也就是”一名多用”。 (二) 為什麼要進行函式過載 一般情況下,編譯器對現有操作符的運算元是有一定的限制,但是

C++派生重寫基過載函式時需要注意的問題:派生函式遮蔽基同名函式

派生類可以繼承基類中的非私有函式成員,當然也就可以繼承其中非私有的被過載的函式。如下: 【參考程式碼】 class Base { public: void print() { cout << "print() in Base." <<

C++模板

類模板(class template)是用來生成類的藍圖,它使類中的一些成員變數和成員函式的引數或返回值可以取任意的資料型別。 1 類模板的宣告 類模板通過關鍵字template來定義,其宣告格式為 template <模板引數列表> class 類名 {   

c++模板過載

#include <iostream> #include <string> #include <sstream> using namespace std; template<typename T> T sum(T *begin, T *end){

C++模板函式及模板的使用(下)

在使用模板類時,一般會將類定義及成員變數和成員函式的宣告放在h標頭檔案中,而將成員函式的定義放在cpp執行檔案中。在編譯程式時可能會出現如下錯誤提示 errorLNK2019: 無法解析的外部符號"public:void __thiscall Stack<int,10

C++過載+運算子易錯點

  我今天晚上覆習C++類的用法,在使用友元過載雙目運算子+的時候,出現了一個詭異的錯誤.百思不得其解,專門重寫一個類進行測試,最後發現了原因.猛然想起我之前也犯過這樣的錯誤,以為經典,故記之.   奉上錯誤程式碼: #include <iostrea