# 🧩 範型(Template)
---
- **學習目標:**
- 了解 C++ 範型(Template)的概念
- 學會使用函式樣板與類別樣板
- 瞭解範型的好處與使用情境
---
## 🔖 什麼是範型?
- **範型(Template)** 是 C++ 提供的一種泛型程式設計機制
- 允許函式或類別能夠處理多種資料型態,而不必重複撰寫程式碼
- 主要分為兩類:
1. **函式樣板(Function Template)**
2. **類別樣板(Class Template)**
---
## 📌 沒有範型時的問題
```cpp
int maxInt(int a, int b) {
return (a > b) ? a : b;
}
double maxDouble(double a, double b) {
return (a > b) ? a : b;
}
```
- 雖然功能一樣,但必須為不同型別重複撰寫程式碼 → 程式碼冗長
---
## 🚩 函式樣板(Function Template)
```cpp
template <typename T>
T myMax(T a, T b) {
return (a > b) ? a : b;
}
```
----
### 使用方式
```cpp
cout << myMax(3, 5) << endl; // int
cout << myMax(3.2, 2.5) << endl; // double
cout << myMax('A', 'Z') << endl; // char
```
---
- 多型(Polymorphism):在執行期決定行為(透過虛擬函式)
- 範型(Template):在編譯期決定型態(編譯器會為不同型別產生對應版本)
---
## 🚩 多參數樣板
```cpp
template <typename T1, typename T2>
void printPair(T1 a, T2 b) {
cout << a << " - " << b << endl;
}
int main() {
printPair(10, 3.14); // int, double
printPair("Age", 25); // const char*, int
}
```
---
## 📌 類別樣板(Class Template)
```cpp
template <typename T>
class Box {
private:
T value;
public:
Box(T v) : value(v) {}
void show() { cout << value << endl; }
};
```
----
### 使用方式:
```cpp
Box<int> b1(123);
Box<string> b2("Hello");
b1.show(); // 123
b2.show(); // Hello
```
---
## 🚩 類別樣板與多個型態參數
```cpp
template <typename T1, typename T2>
class Pair {
private:
T1 first;
T2 second;
public:
Pair(T1 f, T2 s) : first(f), second(s) {}
void show() { cout << first << ", " << second << endl; }
};
Pair<string, int> p("Age", 20);
p.show(); // Age, 20
```
---
### 📗 範型與預設參數
```cpp
template <typename T = int>
class Number {
private:
T value;
public:
Number(T v) : value(v) {}
void show() { cout << value << endl; }
};
Number<> n1(10); // 預設型態 int
Number<double> n2(3.14);
```
----
### 🚩 範例:泛型 Stack 類別
```cpp
template <typename T>
class Stack {
private:
vector<T> data;
public:
void push(T value) { data.push_back(value); }
void pop() { data.pop_back(); }
T top() { return data.back(); }
bool empty() { return data.empty(); }
};
Stack<int> s;
s.push(10);
s.push(20);
cout << s.top(); // 20
```
---
## ⚠️ 範型注意事項
- 範型會在編譯期產生對應型態的程式碼
- 若型態不支援使用的運算子,會導致編譯錯誤
- 範型定義必須與實作放在同一個 .h 檔案(否則可能連結錯誤)
---
## 🛠️ 課堂練習 (Lab)
- 練習一
- 撰寫一個 swapValues 函式樣板,能交換任意型態的兩個變數。
- 練習二
- 實作一個 Stack 類別樣板。
Note:
```cpp
#pragma once
#include <vector>
#include <stdexcept>
#include <utility>
#include <cstddef>
template <typename T>
class Stack {
public:
using value_type = T;
using size_type = std::size_t;
using reference = value_type&;
using const_reference = const value_type&;
Stack() = default;
template <class It>
Stack(It first, It last) : data_(first, last) {}
bool empty() const { return data_.empty(); }
size_type size() const { return data_.size(); }
void clear() { data_.clear(); }
// push:同時支援 lvalue / rvalue
void push(const T& v) { data_.push_back(v); }
void push(value_type&& v) { data_.push_back(std::move(v)); }
// 就地建構,回傳頂端元素參考以便鏈式使用
template <class... Args>
reference emplace(Args&&... args) {
data_.emplace_back(std::forward<Args>(args)...);
return data_.back();
}
// 取頂端;空堆疊時丟出例外
T& top() {
if (empty()) throw std::out_of_range("Stack::top on empty stack");
return data_.back();
}
const T& top() const {
if (empty()) throw std::out_of_range("Stack::top on empty stack");
return data_.back();
}
// 彈出;空堆疊時丟出例外
void pop() {
if (empty()) throw std::out_of_range("Stack::pop on empty stack");
data_.pop_back();
}
// 強例外安全的 swap
void swap(Stack& other) noexcept(noexcept(data_.swap(other.data_))) {
data_.swap(other.data_);
}
private:
std::vector<T> data_;
};
```
```cpp
// main.cpp
#include <iostream>
#include <memory>
#include "stack.hpp"
using std::cout;
int main() {
Stack<int> s;
s.push(10);
s.push(20);
s.emplace(30);
cout << "size=" << s.size() << ", top=" << s.top() << "\n"; // size=3, top=30
s.pop();
cout << "top=" << s.top() << "\n"; // 20
// 字串
Stack<std::string> ss;
ss.emplace("hello");
ss.push(std::string("world"));
cout << ss.top() << "\n"; // world
// 支援移動語意(move-only)
Stack<std::unique_ptr<int>> su;
su.push(std::make_unique<int>(42));
cout << *su.top() << "\n"; // 42
// 建構於迭代器區間
int a[]{1,2,3,4};
Stack<int> s2(std::begin(a), std::end(a));
cout << "s2.top=" << s2.top() << ", size=" << s2.size() << "\n"; // 4, 4
}
```
---
## 💡 本週作業
- 實作一個 MathTool 類別樣板,提供 add, subtract, multiply, divide 四個泛型函式。
{"title":"🧩 第八週:範型(Template)","breaks":true,"description":"學習目標:","contributors":"[{\"id\":\"01487228-6720-47a9-875f-2f01b5d455ad\",\"add\":4773,\"del\":2436,\"latestUpdatedAt\":1755586815163}]"}