天天看點

C++泛型程式設計學習(一)——函數模闆目錄前言模闆概述總結

目錄

  • 目錄
  • 前言
  • 模闆概述
    • 函數模闆
    • 函數模闆文法
    • 函數模闆遇上函數重載
    • 函數模闆原理概述
  • 總結

前言

從接觸到泛型程式設計都現在決定寫部落格,不知道過去多久的時間,感覺每次記得,然後每次都會忘記,是以沒有記錄的工作,基本等于沒做。。某句話就是,一旦你今天想要完成的事情沒有完成,或許你永遠不會再完成它了!

學習!分享!感謝!

模闆概述

函數模闆實際上是建立一個通用函數,其函數類型和形參類型不具體指定,用一個虛拟的類型來代表。這個通用函數就稱為函數模闆。凡是函數體相同的函數都可以用這個模闆來代替,不必定義多個函數,值需要在模闆中定義一次即可。在調用函數時系統會根據實參的類型來取代模闆中的虛拟類型,進而實作不同函數的功能。

C++提供兩種模闆機制:函數模闆和類模闆。類型參數化使得程式可以從邏輯功能上抽象,把被處理的對象(資料)類型作為參數傳遞。

總結:模闆把函數或類要處理的資料類型參數化,表現為參數的多态性,稱為類屬;模闆用于表達邏輯結構相同,但具體資料元素類型不同的資料對象的通用行為。

函數模闆

比如要交換分别char、int、double類型的變量的值,對于函數功能是相同的,但是參數是不同的。也就是說函數功能和資料類型相分離。

函數模闆文法

函數模闆定義形式:

template <類型形式參數表>
類型形式參數的形式為:
typename T1, typename T2, typename Tn
或
class T1, class T2, class T3
           
函數模闆聲明:
template <類型形式參數表>
類型 函數名(形式參數表)
{
    語句序列
}
           

函數模闆定義有模闆說明和函數定義組成

模闆說明的類屬參數必須在函數定義中至少出現一次

函數參數表中可以使用類屬類型參數,也可以使用一般類型參數

函數模闆在使用的時候可以做自動類型推導,也可以顯示調用

#include <iostream>

template <typename T>
T max(T a, T b)
{
    return a>b?a:b;
}
void main()
{
    max(, );         // 自動推導
    max<int>(,);     // 顯式調用
    max('y', 'e');
}
           
  • 舉例
template <typename T1, typename T2>
int mySort(T1 *array, T2 size)
{
    T1 tmp;
    T2 i, j;
    if(array == NULL)
    {
        return -;
    }

    for(i=; i<size; i++)
    {
        for(j=i+; j<size; j++)
        {
            if(array[i] < array[j])
            {
                tmp = array[i];
                array[i] = array[j];
                array[j] = tmp;
            }
        }
    }

    return ;
}

template <typename T1, typename T2>
int myPrint(T1 *array, T2 size)
{
    T2 i;

    for(i=; i<size; i++)
    {
        cout << array[i] << endl;
    }

    return ;
}

int main(void)
{
    int myArray[] = {, , , , , , , , };
    int size = sizeof(myArray)/sizeof(myArray[]);
    mySort<int, int>(myArray, size);

    cout << "after sort" << endl;
    myPrint<int, int>(myArray, size);

    char myCharArray[] = "liuqiang-simon";
    size = strlen(myCharArray);
    mySort<char, int>(myCharArray, size);
    cout << "after sort" << endl;
    myPrint<char, int>(myCharArray, size);  
}
           

函數模闆遇上函數重載

  • 函數模闆和普通函數差別結論:
    1. 函數模闆不允許自動類型轉換,具有嚴格的類型比對。
    2. 普通函數能夠進行自動類型轉換

注意:重寫發生在父類和子類之間,重載發生在同一個作用域。虛函數重寫産生多态;不是虛函數重寫,産生函數重定義,此時父類所有的函數名相同的函數都不能運作。

  • 函數模闆和普通函數在一起,調用規則:
    1. 函數模闆可以像普通函數一樣被重載(參數個數 參數類型 參數順序)
    2. C++編譯器優先考慮普通函數
    3. 如果函數模闆可以産生一個更好的比對,那麼選擇模闆
    4. 可以通過空模闆實參清單的文法限定編譯器隻通過模闆比對
  • 舉例
#include <iostream>
using namespace std;
int Max(int a, int b)
{
    cout<<"int Max(int a, int b)"<<endl;
    return a > b ? a : b;
}

// 模闆
template<typename T>
T Max(T a, T b)
{
    cout<<"T Max(T a, T b)"<<endl;
    return a > b ? a : b;
}

template<typename T>
T Max(T a, T b, T c)
{
    cout<<"T Max(T a, T b, T c)"<<endl;
    return Max(Max(a, b), c);
}

void main()
{
    int a=, b=;
    cout<<Max(a, b)<<endl; // 當函數模闆和普通函數都符合調用時,優先選擇普通函數
    cout<<Max<>(a, b)<<endl; // 若顯式使用函數模闆,則使用<>類型清單
    cout<<Max(, )<<endl; // 如果函數模闆産生更好的比對,使用函數模闆
    cout<<Max(, , )<<endl; // 重載
    cout<<Max('a', )<<endl;      // 調用普通函數 可以隐式類型轉換
}
           

函數模闆原理概述

其實函數模闆中,并不是編譯器把函數模闆處理成能夠處理任意類的函數,編譯器隻是從函數模闆中通過具體類型産生不同的函數。據說,編譯器會對函數模闆進行兩次編譯,在聲明的地方對模闆代碼本身進行編譯;在調用的地方對參數替換後的代碼進行編譯。

C++泛型程式設計學習(一)——函數模闆目錄前言模闆概述總結

由這張圖可知,對程式編譯過程進行說明,從中可以知道要進行預處理、編譯、彙編、連結等過程。在編譯的過程中,第一次編譯先對有函數模闆的地方進行标記,在第二次編譯的時候,在用到函數模闆的地方,對函數進行替換成有具體參數類型的函數。

同時記錄下gcc的編譯指令,以前想要總結一下,不過太麻煩而且不會markdown.

C++泛型程式設計學習(一)——函數模闆目錄前言模闆概述總結

總結

上面都所有代碼都是在一個檔案中,但是實際工作中,我們肯定需要把聲明和定義分别放置在頭檔案和源檔案中,這樣才能夠保證工程的整潔。本節主要是對學過的函數模闆機制進行複習。所有内容都來自于《傳智播客掃地僧c++基礎和進階課堂講義.docx》。以後也是對這份文檔的厚顔抄襲!!!

附上《傳智播客掃地僧c++基礎和進階課堂講義.docx》下載下傳位址。

繼續閱讀