首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ STL 進階(二):模板程式設計與運算子多載實戰

     編輯:關於C++

本章深入探討 STL 核心思想——模板程式設計,並說明運算子多載如何與模板協作,支援泛型演算法。

1. 函數模板:泛型演算法的基石

模板提供參數化型別機制,分為函數模板與類別模板。函數模板類似預處理器巨集但具型別安全性。

範例:陣列求和函數模板

#include 
using namespace std;

// 傳統 int 版本
// int sum(int data[], int nSize) { ... }

// 模板版本:型別參數化
template 
T sum(T data[], int nSize) {
    T total = 0;
    for (int i = 0; i < nSize; i++)
        total += data[i];
    return total;
}

int main() {
    int a[] = {1, 2, 3, 4, 5};
    double b[] = {1.1, 2.2, 3.3};
    cout << "int 陣列總和: " << sum(a, 5) << endl;
    cout << "double 陣列總和: " << sum(b, 3) << endl;
    return 0;
}

template <typename T> 中的 typename 可替換為 class,效果相同。編譯器會根據實際呼叫型別自動具現化函數。

2. 類別模板:動態陣列實作

模擬 std::vector 核心邏輯:動態擴充容量、記憶體管理封裝。

#include 
using namespace std;

template 
class MyArray {
private:
    int m_nTotalSize;   // 總容量
    int m_nValidSize;   // 有效元素數
    T* m_pData;         // 資料指標

public:
    MyArray(int nSize = 2) : m_nTotalSize(nSize), m_nValidSize(0) {
        m_pData = new T[nSize];
    }
    ~MyArray() { delete[] m_pData; }

    int GetValidSize() const { return m_nValidSize; }
    int GetTotalSize() const { return m_nTotalSize; }
    T Get(int pos) const { return m_pData[pos]; }

    void Add(T value) {
        if (m_nValidSize >= m_nTotalSize) {
            // 擴充為兩倍
            T* pOld = m_pData;
            m_nTotalSize *= 2;
            m_pData = new T[m_nTotalSize];
            for (int i = 0; i < m_nValidSize; i++)
                m_pData[i] = pOld[i];
            delete[] pOld;
        }
        m_pData[m_nValidSize++] = value;
    }
};

int main() {
    MyArray arr1;
    arr1.Add(10); arr1.Add(20); arr1.Add(30); // 觸發擴充
    cout << "int 陣列: ";
    for (int i = 0; i < arr1.GetValidSize(); i++)
        cout << arr1.Get(i) << " ";
    cout << endl;

    MyArray arr2;
    arr2.Add(1.5); arr2.Add(2.5);
    cout << "double 陣列: ";
    for (int i = 0; i < arr2.GetValidSize(); i++)
        cout << arr2.Get(i) << " ";
    return 0;
}

此類別展示了 STL 容器「記憶體分配、銷毀、再分配」的核心思想,將記憶體管理細節封裝,使用者無需關心底層操作。

3. Traits 技術:型別特性萃取

STL 強調程式碼重用,traits 技術透過顯式模板特化,萃取不同型別的特性(如回傳型別、參數型別),提供統一介面。

問題情境

有 IntArray 與 FloatArray 兩類別,其 Calculate() 回傳型別與參數型別分別為 int 與 float。欲撰寫統一介面 Array<T>::Calculate() 呼叫它們,但回傳/參數型別不同,難以直接處理。

Traits 解決方案三步驟

// 步驟 1:基本模板類別(可為空)
template 
struct NumTraits { };

// 步驟 2:模板特化,定義型別別名
template <>
struct NumTraits {
    typedef int InputType;
    typedef int ResultType;
};

template <>
struct NumTraits {
    typedef float InputType;
    typedef float ResultType;
};

// 步驟 3:統一介面類別使用 traits
template 
class Array {
public:
    typedef typename NumTraits::ResultType ResultType;
    typedef typename NumTraits::InputType  InputType;

    ResultType Calculate(T& obj, InputType times) {
        return obj.Calculate(times);
    }
};

typename 告訴編譯器 NumTraits<T>::ResultType 是型別而非靜態成員。當 T=IntArray 時,Calculate 簽名自動變為 int Calculate(IntArray&, int);當 T=FloatArray 時變為 float Calculate(FloatArray&, float)。達到型別安全的統一介面。

4. 模板與運算子多載的協作

STL 演算法大量使用模板函數,常需比較、複製、指派等操作,因此自訂型別必須多載對應運算子。

案例:泛型比較函數

#include 
#include 
using namespace std;

template 
bool Greater(U const& u, V const& v) {
    return u > v;  // 需要型別支援 operator>
}

class Student {
    string m_name;
    int m_grade;
public:
    Student(string name, int grade) : m_name(name), m_grade(grade) {}
    // 多載 > 運算子,支援與 int 比較
    bool operator>(int const& value) const {
        return m_grade > value;
    }
};

int main() {
    Student s("Raito", 100);
    cout << boolalpha << Greater(s, 99) << endl; // true
    cout << Greater(2, 1) << endl;               // true (內建型別)
    return 0;
}

若 Student 未多載 operator>,Greater(s, 99) 將編譯失敗。模板函數提供演算法框架,運算子多載提供型別專屬的操作介面,兩者缺一不可。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved