C++模板介紹

2023-09-12 18:01:23

C++ 模板

C++ 模板是一種強大的泛型程式設計工具,它允許我們編寫通用的程式碼,可以用於處理多種不同的資料型別。模板允許我們在編寫程式碼時將型別作為引數進行引數化,從而實現程式碼的重用性和靈活性。

在 C++ 中,模板由關鍵字 template 開始,並且後面跟著模板參數列。模板引數可以是型別引數或非型別引數。

1、模板的基本語法

1.1 型別模板引數(函數模板)

型別模板引數允許我們在定義模板時指定一個或多個型別引數,這些型別引數可以在模板的定義中使用。例如,下面是一個簡單的模板函數範例:

template <typename T>
T add(T a, T b) {
    return a + b;
}

int main() {
    std::cout << add<int>(1,1);   // 輸出:2   顯示指定模板引數型別
    std::cout << add(1.1, 2.2);   // 輸出:3.3   自動推導模板引數型別為浮點型

    return 0;
}

在這個例子中,T 是型別模板引數,它代表一個預留位置型別。我們可以在模板函數 add 中使用 T 來進行引數和返回型別的宣告。當我們呼叫 add 函數時,編譯器會根據傳入的實際型別來推斷 T 的值。

1.2 非型別模板引數(類別範本)

非型別模板引數允許我們在定義模板時指定一個或多個非型別引數,這些引數可以是整數、列舉、指標或參照。非型別引數的值在編譯時確定,且在模板的每個範例化中都是常數。例如,下面是一個使用非型別引數的模板類範例:

template <int Size>
class Array {
private:
    int data[Size];
public:
    // 建構函式
    Array() {
        for (int i = 0; i < Size; ++i) {
            data[i] = i;
        }
    }

    void print() const {
        for (int i = 0; i < Size; i++) {
            std::cout << data[i] << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    Array<5> arr5;    
    Array<10> arr10;   
    arr5.print();// 輸出:0 1 2 3 4
    arr10.print();// 輸出:0 1 2 3 4 5 6 7 8 9
    return 0;
}

在這個例子中,Size 是非型別模板引數,它代表陣列的大小。我們可以在模板類 Array 的定義中使用 Size 來宣告陣列的大小,並在建構函式中初始化陣列。

 

2、模板作用及優勢

模板在 C++ 中具有重要的作用和優勢,可以提高程式碼的重用性和靈活性

2.1.程式碼重用:

模板允許我們編寫通用的程式碼,可以處理多種不同的資料型別,而無需為每種型別編寫重複的程式碼。下面是一個模板函數範例,用於計算陣列的總和:

#include <iostream>

template <typename T, size_t Size>
T sumArray(T (&arr)[Size]) {
    T sum = T();
    for (size_t i = 0; i < Size; ++i) {
        sum += arr[i];
    }
    return sum;
}

int main() {
    int intArray[] = {1, 2, 3, 4, 5};
    double doubleArray[] = {1.1, 2.2, 3.3, 4.4, 5.5};

    int intSum = sumArray(intArray);
    double doubleSum = sumArray(doubleArray);

    std::cout << "Sum of intArray: " << intSum << std::endl;
    std::cout << "Sum of doubleArray: " << doubleSum << std::endl;

    return 0;
}

在這個範例中,我們定義了一個模板函數 sumArray,它可以接受任意型別的陣列作為引數,並計算陣列的總和。通過使用模板,我們可以在不修改程式碼的情況下重複使用這個函數,適用於不同型別的陣列。

2.2.型別安全:

模板在編譯時進行型別檢查,可以提供更好的型別安全性。下面是一個模板類範例,用於實現一個簡單的棧資料結構:

#include <iostream>
#include <vector>

template <typename T>
class Stack {
private:
    std::vector<T> stack;

public:
    void push(const T& item) {
        stack.push_back(item);
    }

    T pop() {
        if (stack.empty()) {
            throw std::runtime_error("Stack is empty");
        }
        T item = stack.back();
        stack.pop_back();
        return item;
    }

    bool isEmpty() const {
        return stack.empty();
    }
};

int main() {
    Stack<int> intStack;
    intStack.push(10);
    intStack.push(20);
    intStack.push(30);

    while (!intStack.isEmpty()) {
        std::cout << intStack.pop() << " ";
    }
    // 輸出: 30 20 10

    std::cout << std::endl;

    Stack<std::string> stringStack;
    stringStack.push("Hello");
    stringStack.push("World");

    while (!stringStack.isEmpty()) {
        std::cout << stringStack.pop() << " ";
    }
    // 輸出: World Hello

    return 0;
}

在這個範例中,我們定義了一個模板類 Stack,它可以儲存任意型別的元素。通過使用模板,我們可以在編譯時檢查型別的一致性,並避免將錯誤型別的元素推入棧中。

 

3、C++中的模板與 Java中的泛型的異同

C++中的模板和 Java中的泛型都是泛型程式設計的概念,它們都可以用於編寫通用的程式碼,以便在多個型別上重複使用。

3.1.相同點

  1. 都可以使用泛型來編寫通用的程式碼,以便在多個型別上重複使用。

  2. 都允許在編譯時進行型別檢查,以避免在執行時出現型別錯誤。

  3. 都可以使用型別引數來表示通用的型別。

3.2.主要不同點

  1. 語法不同:C++中的模板使用template關鍵字來宣告模板引數,而 Java中的泛型使用<>符號來宣告型別引數。

  2. 支援的型別不同:在C++中,模板可以使用任何可用的型別,包括內建型別和自定義型別,而在 Java中,泛型不能接受基本型別作為型別引數――它只能接受參照型別。這意味著可以定義 List<Integer>,但是不可以定義 List<int>

  3. C++中,引數型別不同,範例型別也不同。而在 Java中,不管型別引數是什麼,所有範例都是同一型別,並且型別引數會在執行時被抹去。即,儘管在編譯時 ArrayList<String>ArrayList<Integer> 是兩種型別,但是在執行時只有ArrayList被載入到 JVM中。

  4. Java中,在類/介面上宣告的泛型,在本類或本介面中即代表某種型別,可以作為非靜態屬性的型別、非靜態方法的引數型別、非靜態方法的返回值型別。但是在靜態方法中不能使用類的泛型(因為類的泛型在建立物件時,即範例化時才指定,而靜態方法要早於物件的建立,此時類的泛型還沒指定而靜態結構已經需要使用了)。C++中,型別引數可以用於靜態方法和靜態變數

.....

綜上所述,雖然C++中數模板和 Java中的泛型都是泛型程式設計的概念,但它們在實現上有很大差異。

 

參考資料:

【C++基礎語法】

https://blog.csdn.net/hxhxhxhxx/article/details/119334165

【C++模板和泛型詳解】

https://blog.csdn.net/jj6666djdbbd/article/details/127155728

【C++泛型和 Java泛型的異同】

https://blog.csdn.net/cnds123/article/details/130778765

https://blog.csdn.net/coding_is_fun/article/details/81564512