[C++ OOP Thực Chiến] Bài 32: Toán tử tiền tố (Prefix Operator) - Tăng trước, tính sau!
Chào anh em! Trong các vòng lặp for hay while, chúng ta dùng ++i và i++ nhiều như cơm bữa. Đối với kiểu int, cả hai đều là cộng thêm 1 đơn vị.
Nhưng khi đưa vào một biểu thức phức tạp như int a = ++i;, câu chuyện bắt đầu rẽ nhánh:
- Tiền tố (
++i): Tăng biếnilên 1 TRƯỚC, sau đó mới lấy giá trị mới đó gán choa. (Tăng trước, tính sau).
Hôm nay, chúng ta sẽ nạp chồng toán tử tiền tố ++ cho Class PhanSo. Trong toán học, tăng 1 đơn vị cho phân số nghĩa là: . Tức là ta chỉ cần lấy Tử số cộng thêm Mẫu số là xong!
1. Phân tích Cú pháp & Luật chơi
Vì toán tử tiền tố ++ps là toán tử 1 ngôi và tác động trực tiếp lên chính Object gọi nó, cách tốt nhất là triển khai nó dưới dạng Member Function (Hàm thành viên bên trong Class).
- Tham số: KHÔNG CÓ (Vì nó dùng luôn con trỏ
this). - Chữ
const: KHÔNG ĐƯỢC DÙNG (Vì bản chất của phép++là làm thay đổi giá trị của Object gốc).
2. Bí mật của Giá trị trả về: Tại sao lại là Tham chiếu (&)?
Đây là câu hỏi phân loại ứng viên khi phỏng vấn C++.
Kiểu trả về của hàm operator++() bắt buộc phải là Tham chiếu (PhanSo&), chứ không phải là một Object tạo mới (PhanSo). Tại sao?
C++ cho phép bạn viết những đoạn code "ảo ma" như thế này: ++(++ps);
- Lần 1:
++pschạy, tăng phân số lên 1, và nó phải trả về chính cái phân số gốc đó. - Lần 2: Phép
++bên ngoài tiếp tục bám vào cái phân số gốc vừa được trả về để tăng thêm 1 lần nữa.
Nếu bạn trả về một bản copy (bỏ dấu &), phép ++ thứ 2 sẽ tăng giá trị trên một cái bản sao rác vô danh, và Object gốc của bạn bị sai logic hoàn toàn!
3. Code Demo: Tăng tốc Phân số
Hãy cùng xem cách triển khai cực kỳ ngắn gọn bên trong pháo đài Class:
#include <iostream>
#include <cmath>
using namespace std;
class PhanSo {
private:
int tuSo;
int mauSo;
void rutGon() {
if (mauSo == 0) mauSo = 1;
if (mauSo < 0) { tuSo = -tuSo; mauSo = -mauSo; }
int a = abs(tuSo), b = abs(mauSo);
while (b != 0) { int temp = b; b = a % b; a = temp; }
int ucln = (a == 0) ? 1 : a;
tuSo /= ucln; mauSo /= ucln;
}
public:
PhanSo(int tu = 0, int mau = 1) : tuSo(tu), mauSo(mau) { rutGon(); }
friend ostream& operator<<(ostream& os, const PhanSo& ps) {
if (ps.mauSo == 1) os << ps.tuSo;
else if (ps.tuSo == 0) os << "0";
else os << ps.tuSo << "/" << ps.mauSo;
return os;
}
// --- NẠP CHỒNG TOÁN TỬ TIỀN TỐ (++ps) ---
// Trả về tham chiếu của chính Object hiện tại (*this)
PhanSo& operator++() {
// Tăng phân số lên 1: (a/b) + 1 = (a+b)/b
this->tuSo = this->tuSo + this->mauSo;
// Trút gọn lại cho an toàn
this->rutGon();
// Trả về chính Object đang gọi hàm
return *this;
}
};
int main() {
cout << "--- HE THONG TOAN TU TIEN TO ---\n";
PhanSo ps(1, 2); // 1/2
cout << "Ban dau: ps = " << ps << "\n";
// 1. Tăng bình thường
++ps;
cout << "Sau khi ++ps: ps = " << ps << "\n"; // (1+2)/2 = 3/2
// 2. Tăng và gán cùng lúc (Tăng trước, gán sau)
PhanSo a = ++ps;
cout << "\nThu nghiem: a = ++ps\n";
cout << "-> Gia tri cua a : " << a << "\n"; // 5/2
cout << "-> Gia tri cua ps: " << ps << "\n"; // 5/2 (Cả 2 giống nhau)
// 3. Test cú pháp lồng nhau ảo ma
++(++ps);
cout << "\nSau khi ++(++ps): ps = " << ps << "\n"; // (5+2+2)/2 = 9/2
return 0;
}
Nhận xét: Việc trả về *this (giá trị mà con trỏ this đang trỏ tới) và ép kiểu trả về là tham chiếu (&) đã giúp toán tử tiền tố của chúng ta hoạt động mượt mà, tuân thủ đúng 100% định luật toán học của C++ nguyên thủy.
Tạm kết & Gợi mở
Xong tiền tố! Code khá nhàn và cực kỳ hợp logic. Nhưng khoan...
Toán tử Tiền tố ++ps và Hậu tố ps++ đều dùng chung một ký hiệu là dấu cộng kép ++.
Nếu chúng ta tiếp tục viết thêm một hàm PhanSo& operator++() cho cái Hậu tố, trình biên dịch C++ sẽ báo lỗi trùng lặp (Duplicate) ngay lập tức vì 2 hàm có tên và tham số giống hệt nhau!
Làm sao để C++ phân biệt được khi nào người dùng gõ ++ps (Tiền tố) và khi nào người dùng gõ ps++ (Hậu tố) để gọi đúng hàm?
Có một cú "hack" cực kỳ dị biệt của những nhà sáng lập C++ để xử lý vụ này. Hẹn gặp lại anh em ở Bài 33: Toán tử hậu tố (Postfix Operator) - Tham số bù nhìn và cú lừa lịch sử! Nhớ thả Upvote để tiếp lửa cho series nhé!
All rights reserved