CRTP (Curiously Recurring Template Pattern) là gì?
CRTP (Curiously Recurring Template Pattern) là một kỹ thuật lập trình trong C++ mà một lớp con kế thừa từ một lớp cha, trong đó lớp cha lại sử dụng lớp con làm tham số template. Cách tiếp cận này thường được sử dụng để thực hiện static polymorphism (đa hình tĩnh), giúp tối ưu hiệu suất bằng cách thay thế dynamic polymorphism (đa hình động) sử dụng con trỏ ảo (virtual
).
Cấu trúc cơ bản của CRTP:
template <typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() {
std::cout << "Derived implementation\n";
}
};
int main() {
Derived d;
d.interface(); // Gọi Derived::implementation()
}
Trong đoạn code trên:
- Lớp
Base<Derived>
chứa một phương thứcinterface()
gọiimplementation()
của lớp con (Derived
) bằng cách ép kiểustatic_cast<Derived*>(this)
. - Lớp
Derived
kế thừa từBase<Derived>
và cung cấp triển khai cụ thể choimplementation()
. - Khi gọi
d.interface()
, nó thực sự gọiDerived::implementation()
, mà không cần đến bảng vtable như trong cơ chế đa hình động.
Lợi ích của CRTP
- Đa hình tĩnh (Static Polymorphism)
- CRTP cho phép đa hình mà không cần sử dụng con trỏ ảo (
virtual
), giúp tối ưu hiệu suất vì tránh được overhead của vtable.
- CRTP cho phép đa hình mà không cần sử dụng con trỏ ảo (
- Code Reuse (Tái sử dụng mã)
- CRTP có thể được dùng để tạo các mô hình chung mà lớp con có thể kế thừa, giúp tránh lặp lại code.
- Compile-time Polymorphism (Đa hình thời gian biên dịch)
- Vì tất cả các phương thức được xác định tại thời gian biên dịch, trình biên dịch có thể tối ưu mã tốt hơn.

Ứng dụng của CRTP
1. Tự động cung cấp phương thức interface cho lớp con
CRTP có thể dùng để tạo một interface mà lớp con phải tuân theo:
template <typename Derived>
class Printable {
public:
void print() {
static_cast<Derived*>(this)->printImpl();
}
};
class MyClass : public Printable<MyClass> {
public:
void printImpl() {
std::cout << "Printing MyClass\n";
}
};
int main() {
MyClass obj;
obj.print(); // Gọi MyClass::printImpl()
}
2. Tạo Counter cho từng lớp con
CRTP có thể được sử dụng để đếm số lượng instance của mỗi lớp con:
template <typename Derived>
class Counter {
private:
static int count;
public:
Counter() { ++count; }
~Counter() { --count; }
static int getCount() { return count; }
};
template <typename Derived>
int Counter<Derived>::count = 0;
class A : public Counter<A> {};
class B : public Counter<B> {};
int main() {
A a1, a2;
B b1;
std::cout << "A count: " << A::getCount() << "\n"; // 2
std::cout << "B count: " << B::getCount() << "\n"; // 1
}
- Ở đây,
Counter<A>
vàCounter<B>
có bộ đếm riêng biệt vìA
vàB
là các lớp con khác nhau.
3. Mixin Pattern (Thêm chức năng vào lớp con)
CRTP có thể được sử dụng như Mixin để thêm chức năng vào lớp mà không cần đa kế thừa.
Ví dụ: Thêm logging vào một lớp:
template <typename Derived>
class Logger {
public:
void log(const std::string& message) {
std::cout << "[LOG] " << message << std::endl;
}
};
class Application : public Logger<Application> {
public:
void run() {
log("Application is running");
}
};
int main() {
Application app;
app.run();
}
- Ở đây, lớp
Application
kế thừaLogger<Application>
, nhờ đó nó có thể sử dụng phương thứclog()
mà không cần tạo thêm biến logger.
So sánh CRTP với Đa hình động (virtual
)
Đặc điểm | CRTP (Static Polymorphism) | Virtual Function (Dynamic Polymorphism) |
---|---|---|
Cách triển khai | Template | Dùng con trỏ ảo (virtual ) |
Overhead | Không cần vtable | Cần vtable |
Tốc độ thực thi | Nhanh hơn | Chậm hơn |
Linh hoạt | Giới hạn ở compile-time | Linh hoạt hơn ở runtime |
Tổng kết
- CRTP là một mẫu thiết kế giúp đạt được đa hình tĩnh, thay thế con trỏ ảo (
virtual
). - Được sử dụng để tái sử dụng mã, thêm chức năng (Mixin), đếm số lượng đối tượng, v.v.
- Tối ưu hiệu suất hơn so với đa hình động (
virtual
), nhưng không linh hoạt bằng vì các kiểu phải được biết tại thời gian biên dịch.
Nếu bạn muốn xây dựng một hệ thống hiệu suất cao mà vẫn tận dụng tính kế thừa, CRTP là một lựa chọn mạnh mẽ trong C++. 🚀