Giao diện
📦 Class Templates — Generic Classes
Class templates cho phép tạo generic containers và data structures — giống như
std::vector<T>. Cú pháp cơ bản
cpp
template<typename T>
class Box {
private:
T value_;
public:
Box(T value) : value_(value) {}
T getValue() const { return value_; }
void setValue(T value) { value_ = value; }
};
int main() {
Box<int> intBox(42);
Box<std::string> strBox("Hello");
Box<double> doubleBox(3.14);
std::cout << intBox.getValue() << std::endl; // 42
std::cout << strBox.getValue() << std::endl; // Hello
return 0;
}Template Visualization
┌─────────────────────────────────────────────────────────────────┐
│ CLASS TEMPLATE INSTANTIATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Template: template<typename T> class Box { T value_; } │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ Box<int> Box<double> Box<string> │
│ ┌───────┐ ┌─────────┐ ┌──────────┐ │
│ │int │ │double │ │string │ │
│ │value_ │ │value_ │ │value_ │ │
│ └───────┘ └─────────┘ └──────────┘ │
│ │
│ 3 SEPARATE classes generated at compile time! │
│ │
└─────────────────────────────────────────────────────────────────┘Complete Box<T> Example
cpp
#include <iostream>
#include <stdexcept>
template<typename T>
class Box {
private:
T* data_;
bool hasValue_;
public:
// Default constructor
Box() : data_(nullptr), hasValue_(false) {}
// Value constructor
explicit Box(const T& value)
: data_(new T(value)), hasValue_(true) {}
// Copy constructor
Box(const Box& other)
: data_(other.hasValue_ ? new T(*other.data_) : nullptr),
hasValue_(other.hasValue_) {}
// Move constructor
Box(Box&& other) noexcept
: data_(other.data_), hasValue_(other.hasValue_) {
other.data_ = nullptr;
other.hasValue_ = false;
}
// Destructor
~Box() {
delete data_;
}
// Copy assignment
Box& operator=(const Box& other) {
if (this != &other) {
delete data_;
data_ = other.hasValue_ ? new T(*other.data_) : nullptr;
hasValue_ = other.hasValue_;
}
return *this;
}
// Move assignment
Box& operator=(Box&& other) noexcept {
if (this != &other) {
delete data_;
data_ = other.data_;
hasValue_ = other.hasValue_;
other.data_ = nullptr;
other.hasValue_ = false;
}
return *this;
}
// Access
bool hasValue() const { return hasValue_; }
T& value() {
if (!hasValue_) throw std::runtime_error("Box is empty");
return *data_;
}
const T& value() const {
if (!hasValue_) throw std::runtime_error("Box is empty");
return *data_;
}
// Get or default
T valueOr(const T& defaultValue) const {
return hasValue_ ? *data_ : defaultValue;
}
};
int main() {
Box<int> box1(42);
Box<int> box2; // Empty
std::cout << box1.value() << std::endl; // 42
std::cout << box2.valueOr(0) << std::endl; // 0
Box<std::string> strBox("Hello");
strBox.value() += " World";
std::cout << strBox.value() << std::endl; // Hello World
return 0;
}Multiple Template Parameters
cpp
template<typename K, typename V>
class Pair {
private:
K key_;
V value_;
public:
Pair(const K& key, const V& value) : key_(key), value_(value) {}
K& key() { return key_; }
const K& key() const { return key_; }
V& value() { return value_; }
const V& value() const { return value_; }
};
int main() {
Pair<std::string, int> age("Alice", 25);
Pair<int, double> coord(10, 3.14);
std::cout << age.key() << ": " << age.value() << std::endl;
// Alice: 25
return 0;
}Member Functions Outside Class
cpp
template<typename T>
class Stack {
private:
std::vector<T> data_;
public:
void push(const T& value);
void pop();
T& top();
const T& top() const;
bool empty() const;
std::size_t size() const;
};
// Định nghĩa bên ngoài — phải repeat template<typename T>
template<typename T>
void Stack<T>::push(const T& value) {
data_.push_back(value);
}
template<typename T>
void Stack<T>::pop() {
if (data_.empty()) {
throw std::runtime_error("Stack is empty");
}
data_.pop_back();
}
template<typename T>
T& Stack<T>::top() {
if (data_.empty()) {
throw std::runtime_error("Stack is empty");
}
return data_.back();
}
template<typename T>
const T& Stack<T>::top() const {
if (data_.empty()) {
throw std::runtime_error("Stack is empty");
}
return data_.back();
}
template<typename T>
bool Stack<T>::empty() const {
return data_.empty();
}
template<typename T>
std::size_t Stack<T>::size() const {
return data_.size();
}Non-type Template Parameters
cpp
template<typename T, std::size_t Capacity>
class FixedArray {
private:
T data_[Capacity];
std::size_t size_ = 0;
public:
void push_back(const T& value) {
if (size_ >= Capacity) {
throw std::overflow_error("Array is full");
}
data_[size_++] = value;
}
T& operator[](std::size_t index) {
return data_[index];
}
constexpr std::size_t capacity() const { return Capacity; }
std::size_t size() const { return size_; }
};
int main() {
FixedArray<int, 10> arr; // Fixed capacity of 10
arr.push_back(1);
arr.push_back(2);
std::cout << "Capacity: " << arr.capacity() << std::endl; // 10
std::cout << "Size: " << arr.size() << std::endl; // 2
return 0;
}Default Template Arguments
cpp
template<typename T = int, typename Allocator = std::allocator<T>>
class MyVector {
private:
T* data_;
std::size_t size_;
std::size_t capacity_;
Allocator alloc_;
public:
// Implementation...
};
int main() {
MyVector<> v1; // T=int, Allocator=std::allocator<int>
MyVector<double> v2; // T=double, Allocator=std::allocator<double>
MyVector<int, CustomAlloc> v3; // Custom allocator
return 0;
}Nested Classes
cpp
template<typename T>
class LinkedList {
public:
// Nested Node class
struct Node {
T data;
Node* next;
Node(const T& d) : data(d), next(nullptr) {}
};
private:
Node* head_ = nullptr;
public:
void pushFront(const T& value) {
Node* newNode = new Node(value);
newNode->next = head_;
head_ = newNode;
}
~LinkedList() {
while (head_) {
Node* temp = head_;
head_ = head_->next;
delete temp;
}
}
};Template Friends
cpp
template<typename T>
class Box;
// Forward declare operator<<
template<typename T>
std::ostream& operator<<(std::ostream& os, const Box<T>& box);
template<typename T>
class Box {
private:
T value_;
public:
Box(T value) : value_(value) {}
// Friend declaration cho template operator<<
friend std::ostream& operator<< <T>(std::ostream& os, const Box<T>& box);
};
// Definition
template<typename T>
std::ostream& operator<<(std::ostream& os, const Box<T>& box) {
return os << "Box(" << box.value_ << ")";
}
int main() {
Box<int> box(42);
std::cout << box << std::endl; // Box(42)
return 0;
}Practical Example: SimpleOptional
cpp
template<typename T>
class SimpleOptional {
private:
alignas(T) unsigned char storage_[sizeof(T)];
bool hasValue_ = false;
T* ptr() { return reinterpret_cast<T*>(storage_); }
const T* ptr() const { return reinterpret_cast<const T*>(storage_); }
public:
SimpleOptional() = default;
SimpleOptional(const T& value) : hasValue_(true) {
new (storage_) T(value);
}
~SimpleOptional() {
if (hasValue_) {
ptr()->~T();
}
}
explicit operator bool() const { return hasValue_; }
T& operator*() { return *ptr(); }
const T& operator*() const { return *ptr(); }
T* operator->() { return ptr(); }
const T* operator->() const { return ptr(); }
};
int main() {
SimpleOptional<std::string> opt("Hello");
if (opt) {
std::cout << *opt << std::endl; // Hello
std::cout << opt->length() << std::endl; // 5
}
return 0;
}📚 Tổng kết
| Feature | Example |
|---|---|
| Basic class template | template<typename T> class Box { T value_; }; |
| Multiple params | template<typename K, typename V> class Pair { }; |
| Non-type param | template<typename T, int N> class Array { T data_[N]; }; |
| Default | template<typename T = int> class Container { }; |
| Member outside | template<typename T> void Stack<T>::push(...) { } |
➡️ Tiếp theo
Tiếp theo: Template Specialization — Handle edge cases.