Nạp chồng toán tử (Operator Overloading)
Nạp chồng toán tử (operator overloading) cho phép định nghĩa lại ý nghĩa của các toán tử (+, -, ==, <<…) khi áp dụng lên object do bạn tự định nghĩa - giúp code dùng class trông tự nhiên như dùng kiểu dữ liệu có sẵn (int, double…).
Vấn đề: toán tử không tự hiểu object của bạn
Phần tiêu đề “Vấn đề: toán tử không tự hiểu object của bạn”class Point {public: double x, y; Point(double x, double y) : x(x), y(y) {}};
int main() { Point p1(1, 2), p2(3, 4); // Point p3 = p1 + p2; // LỖI! Trình biên dịch không biết cộng hai Point nghĩa là gì return 0;}Nạp chồng toán tử + bằng hàm thành viên
Phần tiêu đề “Nạp chồng toán tử + bằng hàm thành viên”#include <iostream>
class Point {public: double x, y; Point(double x, double y) : x(x), y(y) {}
Point operator+(const Point& other) { // Nạp chồng toán tử + return Point(x + other.x, y + other.y); }};
int main() { Point p1(1, 2), p2(3, 4); Point p3 = p1 + p2; // Tương đương p1.operator+(p2)
std::cout << p3.x << ", " << p3.y << std::endl; // 4, 6
return 0;}Nạp chồng toán tử so sánh ==
Phần tiêu đề “Nạp chồng toán tử so sánh ==”class Point {public: double x, y; Point(double x, double y) : x(x), y(y) {}
bool operator==(const Point& other) { return x == other.x && y == other.y; }};
int main() { Point p1(1, 2), p2(1, 2); if (p1 == p2) { // Tương đương p1.operator==(p2) std::cout << "Hai diem trung nhau" << std::endl; } return 0;}Nạp chồng << để in object ra cout
Phần tiêu đề “Nạp chồng << để in object ra cout”Toán tử << không phải là hàm thành viên của Point (vế trái là std::cout, không phải Point), nên phải nạp chồng bằng hàm tự do (free function), không phải hàm thành viên. Cần khai báo friend để hàm này truy cập được thành viên private (nếu có) của class:
#include <iostream>
class Point {public: double x, y; Point(double x, double y) : x(x), y(y) {}
friend std::ostream& operator<<(std::ostream& os, const Point& p);};
std::ostream& operator<<(std::ostream& os, const Point& p) { os << "(" << p.x << ", " << p.y << ")"; return os; // Trả về os để có thể nối chuỗi << << như bình thường}
int main() { Point p1(3, 4); std::cout << "Diem: " << p1 << std::endl; // Diem: (3, 4)
return 0;}Bảng các toán tử thường được nạp chồng
Phần tiêu đề “Bảng các toán tử thường được nạp chồng”| Toán tử | Ý nghĩa thường gặp khi nạp chồng |
|---|---|
+, -, *, / |
Phép toán số học giữa hai object |
==, != |
So sánh bằng/khác nhau |
<, > |
So sánh thứ tự (hữu ích khi sắp xếp object) |
<<, >> |
Xuất/nhập object qua cout/cin |
[] |
Truy cập phần tử như mảng (ví dụ trong class tự viết kiểu vector) |
() |
Gọi object như một hàm (functor) |
Lưu ý: đừng lạm dụng
Phần tiêu đề “Lưu ý: đừng lạm dụng”Chỉ nạp chồng toán tử khi ý nghĩa thật sự trực quan và tự nhiên (ví dụ + để cộng hai vector toán học). Nếu hành vi không rõ ràng, nên dùng một hàm thành viên có tên mô tả rõ ràng (ví dụ combine()) thay vì ép người đọc phải đoán operator+ làm gì.
Tổng kết
Phần tiêu đề “Tổng kết”- Nạp chồng toán tử cho phép các toán tử quen thuộc (
+,==,<<…) hoạt động trên object tự định nghĩa - Toán tử mà vế trái là object của class (
+,==…) thường nạp chồng bằng hàm thành viên:KieuTraVe operator@(...) - Toán tử mà vế trái không phải object của class (như
<<vớistd::cout) phải nạp chồng bằng hàm tự do, thường cần khai báofriend - Chỉ nạp chồng khi ý nghĩa toán tử thật sự trực quan, tránh gây khó hiểu cho người đọc code