1. 程式人生 > >【C++入門筆記】函式模板

【C++入門筆記】函式模板

此文為FishC大佬《C++快速入門》第四十四講函式模板的筆記整理。

基本的模板語法

到目前為止,我們已經介紹了兩種C++程式設計範型,即:

  1. 按照面向過程式範型把程式劃分為不同的函式
  2. 按照面向過程式範型把程式碼和資料組織成各種各樣的類並建立類之間的繼承關係。

在這一講裡,將介紹另一種範型:泛型程式設計!

泛型程式設計技術支援程式設計師建立函式和類的藍圖(即模板,template),而不是具體的函式和類。

這些模板可以沒有任何型別:它們可以處理的資料並不僅限於某種特定的資料型別。

當程式需要用到這些函式中的某一個時,編譯器將根據模板即時生成一個能夠對特定資料型別進行處理的程式碼版本。

泛型程式設計技術可以讓程式設計師用一個解決方案解決多個問題。

接下來的這幾講,我們先來學習如何編寫和使用自己的泛型程式碼,然後阻礙跟大家介紹標準模板庫(Standard Template Library,STL)。

在泛型程式設計技術裡,我們仍然需要編寫自己的函式和類,但不必限定它們所使用的資料型別。

只需要使用一個佔位符(通常用字母T表示)然後用這個佔位符來編寫函式。

當程式需要這段程式碼時,你提供資料型別,編譯器將根據你的模板即時生成實用的程式碼。

簡單來說,編譯器把模板裡的每一個T替換成所提供的資料型別。

我們回來說說STL庫,STL庫是泛型程式設計技術的經典之作,它包含了許多非常有用的資料型別和演算法。

以下程式碼定義了一個名為foo()的函式模板:

template<class T>
void foo(T param)
{
    //do something
}

這裡有幾件事情值得注意:

  • 第一行程式碼裡:在尖括號裡有一個class T,用來告訴編譯器:字母T將在接下來的函式裡代表一種不確定的資料型別。
  • 關鍵字class並不意味著這是個類噢,這只是一種約定俗成的寫法而已。
  • 在告訴計算機T是一種型別之後,就可以像對待普通資料型別那樣去使用它了。

 舉個栗子:

交換兩個變數的值是一種幾乎所有的程式都需要用到的基本操作。因為這種交換如此長劍,所以把它編寫成一個函式。

void swap(int &a,int &b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

簡單分析下:如果想用這個函式來交換兩個double型別的變數的值,我們應該怎麼辦?

我們可以再增加一個swap(double &a,double &b)函式,因為C++支援函式過載。

但是我們發覺,不得不為交換的每一種資料型別反覆編寫同樣的程式碼。

這正是函式末班大顯身手的地方,你用不著為每種資料型別分別編寫一個函式,只要告訴編譯器你已經為此準備好了一個模板就行了!

這樣子,等你再使用swap( )函式時,編譯器將根據模板自動建立一個函式,該函式會使用正確的資料型別完成交換變數值的任務。

#include <iostream>
#include <string>

template <class T>
void swap(T &a, T &b)
{
    T tmp = a;
    a = b;
    b = tmp;
}

int main()
{
    int i1 = 100;
    int i2 = 200;

    std::cout << "交換前, i1 = " << i1 << ", i2 = " << i2 << "\n";
    swap(i1, i2);
    std::cout << "交換後, i1 = " << i1 << ", i2 = " << i2 << "\n";

    std::string s1 = "小甲魚";
    std::string s2 = "小由魚";

    std::cout << "交換前, s1 = " << s1 << ", s2 = " << s2 << "\n";
    swap(s1, s2);
    std::cout << "交換後, s1 = " << s1 << ", s2 = " << s2 << "\n";

    return 0;
}

神器的函式模板!簡直是偷懶神器。

在建立模板時,還可以用template<typename T>來代替template<class T>,它們的含義是一樣的。注意:template<class T>中的class並不意味著T只能是一個類。

再強調一次,不要把函式模板分成原型和實現兩個部分。如果編譯器看不到模板的完整程式碼,它就無法正確的生成程式碼。

為了明確表明swap( )是一個函式模板,還可以使用swap<int>(i1,i2)語法來呼叫這個函式。這將明確地告訴編譯器它應該使用哪一種型別。

如果某個函式對所有資料型別都將進行同樣的處理,就應該把它編寫成一個模板。

如果某個函式對不同的資料型別將進行不同的處理,就應該對它進行過載。