日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++函數模板和類模板詳解

作者:小圣編程 更新時間: 2022-07-18 編程語言

泛型編程在實際當中運用很廣泛,它可以不針對某種類型 (例如 int、double、float 等),能適應廣泛的類型,在很多需要重復編寫的代碼當中可以很大程度上減少程序的代碼量,提高效率

我們先思考一下,如何實現一個通用的交換函數呢?

//可以使用之前的函數重載的知識完成
void Swap(int& left, int& right)
{
  int temp = left;
  left = right;
  right = temp;
}
void Swap(double& left, double& right)
{
  double temp = left;
  left = right;
  right = temp;
}
void Swap(char& left, char& right)
{
 char temp = left;
 left = right;
 right = temp;
}

有沒有發現每次增加新的類型就要多添加程序代碼,很麻煩

在我們古代,活字印刷可以將經常使用的文字刻出來方便下次使用,同樣,我們要交換兩個數據的多種類型,就可以使用交換的函數模板

函數模板的使用

使用格式:

template<typename T1>//1個模板參數
template<typename T1, typename T2,......,typename Tn>//也可以多個

我們用函數模板再寫一下上面的交換函數

//用法
template<typename T>//在交換函數上面寫
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

int main()
{
	int a = 0, b = 1;
	double c = 2.2, d = 3.2;

	Swap(a, b);
	Swap(c, d);
	cout << a << " " << b << endl;//打印 1 0
	cout << c << " " << d << endl;//打印 3.2 2.2 
	return 0;
}

函數模板大部分還會自動推導轉換的類型,這時我們只需寫一個交換函數,就可以實現多種類型的交換,很方便

函數模板的實例化

//用法
template<class T>
T Add(const T& left, const T& right)
{
  return left + right;
}
int main()
{
  int a1 = 10, a2 = 20;
  double d1 = 10.0, d2 = 20.0;
  Add(a1, a2);//隱式實例化 都是int 會自動推導int
  Add(a1, d2);//這時兩個類型不同 
  Add<int>((a1, (int)d2);//顯示實例化 我們可以指定算的類型
  return 0;
}

模板參數的匹配原則

我們看一個案例熟悉模板參數的匹配原則

案例:當模板函數和加法函數同時存在

//int的加法函數
int Add(int left, int right)
{
  cout << "調用int加法函數" << endl;
  return left + right;
}

//模板加法函數
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
  cout << "調用模板加法函數" << endl;
  return left + right;
}

void TestAdd1()
{
  int ret=Add(1, 2);    
  cout << ret << endl;//類型都是int 此時會調用int加法函數
  ret=Add(1, 2.0);
  cout << ret << endl;//此時不全是int,會調用模板加法函數
  ret=Add<int>(1, 2.0);
  cout << ret << endl;//實例化后也會調用模板加法函數   
}
int main()
{
  TestAdd1();
}

對于非模板函數和同名函數模板,如果其他條件都相同,在調動時會優先調用非模板函數而 不會從該模板產生出一個實例。如果模板可以產生一個具有更好匹配的函數, 那么將選擇模板

類模板的使用

先看一個我們完成棧的部分編程代碼,此時這個程序只是支持int類型的數據

//棧的實現
class Stack
{
public:
	Stack(int capacity = 0)
	{
		_a = new int[capacity];
		_capacity = capacity;
		_top = 0;
	}
	~Stack()
	{
		delete[]_a;
		_capacity = 0;
		_top = 0;
	}
	void Push(int x)
	{}

private:
	int* _a;
	int _top;
	int _capacity;

};

int main()
{
	Stack st1;
	st1.Push(1);
	Stack st2;
	st2.Push(2.2);
}

我們如果想插入double數據,在數據定義、申請內存、插入數據時都需要修改int,耽誤時間,這時我們就可以使用類模板

類模板使用格式:

template<class T1, class T2, ..., class Tn>
class 類模板名
{
// 類內成員定義
}; 

我們在用類模板寫一下上面的棧實現

template<class T>
class Stack//類模板名
{
public:
	Stack(int capacity = 0)
	{
		_a = new T[capacity];//new capacity個 T類型
		_capacity = capacity;
		_top = 0;
	}
	~Stack()
	{
		delete[]_a;
		_capacity = 0;
		_top = 0;
	}
	void Push(T x)
	{}

private:
	T* _a;
	int _top;
	int _capacity;

};
int main()
{
	Stack<int> st1;//不能自動推導
	st1.Push(1);//調用就可以傳是int的

	Stack<double> st2;
	st2.Push(2.2); //調用就是傳double的
}

使用類模板實現棧我們只需要在mian函數中將實例化的(double或int)類型放在<>中即可,省去我們去函數中一個個修改的時間

類模板的實例化

//類模板實例化與函數模板實例化不同,類模板實例化需要在類模板名字后跟<>,然后將實例化的
//類型放在<>中即可
Vector類名,Vector<int>才是類型
Vector<int> s1;
Vector<double> s2;

注意:類模板名字不是真正的類,而實例化的結果才是真正的類

模板的分離編譯

一個程序(項目)由若干個源文件共同實現,而每個源文件單獨編譯生成目標文件,最后將所有 目標文件鏈接起來形成單一的可執行文件的過程稱為分離編譯模式

注意事項:

當我們把上面加法模板函數聲明和定義分別放在.h和.cpp中時運行

// Add.h
template<class T>
T Add(const T& left, const T& right);
// Add.cpp
template<class T>
T Add(const T& left, const T& right)
{
  return left + right;
}
 //main.cpp
int main()
{
  Add(1, 2);
  Add(1.0, 2.0);
  return 0;
}

當我們把模板函數聲明和定義寫在兩個文件中,會出現以上鏈接錯誤報錯

解決方法:我們將聲明和定義放到一個文件 "xxx.hpp" 里面,就會運行正常

// Add.hpp
template<class T>
T Add(const T& left, const T& right);
template<class T>
T Add(const T& left, const T& right)
{
  return left + right;
}
 
//main.cpp
int main()
{
  Add(1, 2);
  Add(1.0, 2.0);
  return 0;
}

所以,模板函數不支持聲明和定義寫在兩個文件中,會出現鏈接錯誤,如果要分離編譯的話,可以將聲明和定義都放在頭文件中,然后修改文件名后綴為.hpp

想了解更多分離編譯內容的話,可以去這個鏈接http://blog.csdn.net/pongba/article/details/19130

希望這篇文章大家有所收獲,我們下篇見


原文鏈接:https://blog.csdn.net/qq_72486849/article/details/125835436

欄目分類
最近更新