c++類模板深度剖析

一、類模板的泛指類型能夠定義多個

template <typename T1, typename T2>
class Test
{
public:	
	void add(T1 a, T2, b);
};

使用時: Test<int, float> t1;	//T1的泛指類型就是int, T2的泛指類型就是float。

二、類模板的特化類型

(1)意思就是若是定義了一個類模板,這個類模板的參數有多個,可是若是當使用這個類模板的時候,咱們傳遞參數時,參數的類型是同樣的話,編譯器就會將類模板特化成一個參數的類模板。

(2)類模板的特化分爲:部分特化,和徹底特化。

部分特化:用特定規則約束類型參數,部分類型參數必須顯示指定,根據類型參數分開實現類模板
如:

template										特化後				template	
< typename T1, typname T2 >											< typename T >		
class Test															class Test <T, T>	//部分特化的約束條件
{																	{
			
};																	};
當類型參數不一樣的時候,會選擇用左邊的那個類模板,當類型參數相同的時候。class Test< T, T>就是約束條件


徹底特化:徹底顯示指定類型參數
如:
template										特化後				template	
< typename T1, typname T2 >											<  >	//徹底特化時,不須要聲明泛指類型
class Test															class Test <int, int> //這個就是徹底特化
{																	{
			
};																	};
當使用類模板的時候,而且指定了全部的類型參數全都是同樣的,好比int的時候,編譯器就會將左邊的類模板特化成右邊的類模板,此時該類模板中就沒有泛指類型了。
當類型參數不一樣的時候,就會使用左邊的類模板。

(3)根據實驗的例子,類模板的特化就是程序中有了一個左邊的類模板的時候(這個類模板的有兩個泛指類型),可是同時程序中咱們又定義了一個同名的類模板,可是這個類模板的兩個泛指類型都是同樣的。這個時候,當咱們在程序中使用這個類模板的時候,若是參數類型是不同的,編譯器就會使用左邊的那個,若是參數類型是同樣的時候,編譯器就會使用右面的那個。編譯器會認爲右邊的那個類模板,是左邊的類模板的一種特化,編譯器不會認爲左邊的類模板是一個新的類模板,只是一個左邊類模板的一個特化,因此編譯可以經過。

總結:將一個類模板,根據不一樣的類型參數狀況進行分開實現這個類模板,其實就是一個類模板的特化過程。

例:

#include <iostream>

using namespace std;


template 
< typename T1, typename T2 >
class Test
{
public:
	void add(T1 a, T2 b)
	{
		cout << "void add(T1 a, T2 b)" << endl;
		cout << a + b << endl;
	}
};


/*****************************************************部分特化*************************************************/


template
< typename T>
class Test < T, T >		//這個地方加上了約束條件,雖然這個類模板跟上面的那個類模板同名,編譯器不會認爲這個類模板是一個新的類模板,而是上面類模板的一個特化形式,
{				//當咱們使用Test類模板的時候,若是指定的參數類型不一樣的話,編譯器就會使用上面的那個類模板實現,若是指定參數類型相同的話,編譯器就會使用這個類模板的實現
public:
	void add(T a, T b)
	{
		cout << "void add(T a, T b)" << endl;
		cout << a + b << endl;
	}
	void print(void)		//即便多出來了個print成員函數,編譯也是經過的,因此是支持這種特化方式的
	{
		cout << "class Test < T, T >	" << endl;
	}
};

/******************************************************徹底特化**********************************************************/

template
< >		//進行類模板的徹底特化時,不用進行泛指類型的聲明
class Test <void *, void *>		//當使用Test類模板時,參數類型都爲void *時,就會使用這個實現。
{
public:
	void add(void * a, void * b)
	{
		cout << "void add(void * a, void * b)" << endl;
		cout << "Error run not to add because type is void *..." << endl;
	}
};

/*****************************************將Test類模板特化出一個兩個參數分別是指針的狀況**********************************************/

template 
< typename T1, typename T2>
class Test < T1 *, T2 *>
{
public:
	void add(T1 *a, T2 *b)
	{
		cout << "void add(T1 *a, T2 *b)" << endl;
		cout << *a + *b << endl;
	}	
};

int main(void)
{
	int a = 1;
	double b = 1.0;
	
	Test<int, float> t1;	//使用的就是沒有特化的Test類模板
	Test<long, long> t2;	//使用的就是特化後的Test類模板
	Test<void *, void *> t3;
	Test<int *, double *> t4;
	
	t1.add(2, 2.5);
	t2.add(10, 10);
	
	t2.print();
	
	t3.add(&a, &b);
	
	t4.add(&a, &b);
	
	return 0;
}



三、繼續理解類模板的特化

(1)類模板的特化的就是根據須要,將一個類模板進行分開來實現。特化只是模板的分開實現,本質上仍是同一個類模板。特化類模板的使用方式是統一的,就是必須顯示的指定每個類型參數。


(2)問題:類模板特化與重定義有區別嗎?
答:有區別,重定義和特化不一樣。在本質上,若是將一個類模板進行重定義,那麼要麼就是實現了一個新的類,要麼就是最後會出現兩個類模板。本質上不一樣。使用的時候不能進行統一使用,
在使用時咱們要考慮選擇哪一個。

特化的本質是,只實現同一個類模板,只不過這個類模板是分開來實現的,這就是本質上的不一樣。在使用時是用統一的方式進行使用類模板和特化類,由於本質上都是實現了一個類模板,使用時
編譯器會根據不一樣的參數類型來選擇去使用那個類模板仍是特化類。因此類模板的特化就是將一個類模板進行分開來實現,這句話是很是重要的。

(3)問題:函數模板能夠特化嗎?
答:函數模板只支持類型參數的徹底特化,不支持部分特化,也就是在函數名的後面顯示的指定出具體的參數類型。

如:函數模板的徹底特化

template
< typename T >
bool Equal(T a, T b)	//函數模板的定義
{
	return a == b;
}

template	
< >						
bool Equal<void *>(void *, void *)	//函數模板的徹底特化
{
	return a == b;		
}

(4)工程中的建議:當須要重載函數模板的時候,咱們要優先考慮使用模板特化的方式去分開實現一個函數模板,而是不用重載函數模板的方式去新的實現了一個函數,當模板特化沒法知足要
求的時候,在使用函數重載。

工程中使用模板特化來代替類(函數)重定義。


例:類模板的部分特化、徹底特化,函數模板的徹底特化。優先考慮使用特化的方式當須要將模板進行重定義添加功能時。

#include <iostream>
#include <string>

using namespace std;


/*
*	特化的方式實現一個類模板,本質就是分開實現類模板
*
*/
template
<typename T1, typename T2> 
class Why
{
public:
	void print(T1 a, T2 b)
	{
		cout << "void print(T1 a, T2 b)" << endl;
		cout << a << " " << b << endl;
	}
};

template
<typename T>
class Why<T, T>	//爲類模板的部分特化
{
public:
	void print(T a, T b)
	{
		cout << "void print(T a, T b)" << endl;
		cout << a << " " << b << endl;
	}	
};

template
< >
class Why<int, int>		//爲類模板的徹底特化
{
public:
		void print(int a, int b)
		{
			cout << "void print(int a, int b)" << endl;
			cout << a << " " << b << endl;
		}
};

/*
*	函數模板的特化只支持徹底特化
*	實現一個函數模板,而且徹底特化,也就是分開實現一個函數模板,這樣叫作特化。
*/
template 
<typename T>
bool Equal(T a, T b)
{
	return a == b;
}

template
< >		//函數模板的徹底特化,之因此要特化這個函數模板是由於,浮點數的比較不單純的只用==來比較。
bool Equal<double>(double a, double b)
{
	const double delta = 0.00000000001;
	double r = a - b;
	
	cout << "bool Equal<double>(double a, double b)" << endl;
	
	return ((-delta < r) && (r < delta)); 
}

/*
*	重載Equal函數的方式來達到比較浮點數的方法,但這種方式是不優先考慮的,由於這種方式,在使用的時候要考慮如何選擇,要優先考慮使用特化的方式。
*	能使用特化的方式時,就不考慮使用這種函數重載的方式,不論對於類模板仍是函數模板都是這樣的,優先考慮使用特化的方式來分開實現,由於這樣都是爲了實現一個類模板或函數模板。
*/
bool Equal(double a, double b)
{
	const double delta = 0.00000000001;
	double r = a - b;
	
	cout << "bool Equal(double a, double b)" << endl;
	
	return ((-delta < r) && (r < delta));
}


int main(void)
{
	double a = 0.0, b = 0.0;
	
	Why<int, double> w1;
	Why<string, string> w2;
	Why<int, int>w3;
	
	w2.print("why", "fangqingqing");
	w1.print(1, 2.2);
	w3.print(100,100);
	
	cout << "Please input two double number..." << endl;
	
	cin >> a >> b;
	
	cout << Equal<double>(a, b) << endl;
	
	cin >> a >> b;
	
	cout << Equal(a, b) << endl;
	
	
	return 0;
}
相關文章
相關標籤/搜索