Đang tải...

[C++ OOP Thực Chiến] Bài 34: Toán tử so sánh - Cán cân công lý của OOP

09/05/2026
3 phút đọc
[C++ OOP Thực Chiến] Bài 34: Toán tử so sánh - Cán cân công lý của OOP
Chào anh em! Đến thời điểm này, Class `PhanSo` của chúng ta đã có thể tính toán (`+`, `-`, `*`, `/`) và in ấn (``) y hệt một biến int nguyên thủy.Nhưng nếu bạn né...

Chào anh em! Đến thời điểm này, Class PhanSo của chúng ta đã có thể tính toán (+, -, *, /) và in ấn (<<, >>) y hệt một biến int nguyên thủy.Nhưng nếu bạn ném một mảng các PhanSo vào hàm std::sort() của C++, compiler sẽ khóc thét. Tại sao? Vì nó không biết $\frac{1}{2}$ và $\frac{3}{4}$ thằng nào lớn hơn để mà xếp hạng!Đã đến lúc chúng ta nạp chồng các toán tử quan hệ: ==, !=, <, >, <=, >=.

1. Logic So Sánh: Lợi thế tuyệt đối của việc "Rút gọn ngầm"

Trong toán học, để so sánh 2 phân số, chúng ta thường phải quy đồng mẫu số hoặc nhân chéo:$\frac{a}{b} = \frac{c}{d} \iff a \times d = b \times c$Tuy nhiên, hãy nhớ lại thiết kế xuất sắc của chúng ta từ [Bài 20]. Hàm Constructor luôn tự động gọi rutGon() ngay khi Object ra đời. Mọi mẫu số âm đều bị đẩy lên tử số, và phân số luôn ở dạng tối giản.Điều này mang lại một lợi thế cực lớn về mặt hiệu năng (Performance) khi so sánh bằng (==):Thay vì phải nhân chéo tốn CPU, $\frac{2}{4}$ và $\frac{1}{2}$ trong RAM của chúng ta thực chất ĐỀU LÀ $\frac{1}{2}$. Chúng ta chỉ cần so sánh trực tiếp: tuSo == tuSo và mauSo == mauSo là xong!Còn với phép lớn hơn/nhỏ hơn, ta áp dụng nhân chéo một cách an toàn (vì mẫu số luôn dương):$\frac{a}{b} < \frac{c}{d} \iff a \times d < c \times b$

2. Lựa chọn vũ khí: Lại là Hàm bạn (Friend Function)

Giống hệt như phép cộng ở [Bài 29], toán tử so sánh là toán tử 2 ngôi. Nếu chúng ta dùng Member Function, biểu thức 5 == ps1 sẽ bị lỗi compiler ngay lập tức vì số 5 không thể làm chủ nhà.

Do đó, Hàm bạn (Friend) với 2 tham số ngang hàng tiếp tục là chân ái để bảo toàn tính giao hoán. Đặc biệt, kiểu trả về của các hàm này bắt buộc phải là bool (Đúng/Sai).

3. Code Demo: Định nghĩa Cán cân công lý

Hãy cùng xem cách triển khai cực kỳ gọn gàng và chuẩn xác:

#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;
 }

 // --- KHAI BÁO CÁC TOÁN TỬ SO SÁNH (HÀM BẠN) ---
 friend bool operator==(const PhanSo& a, const PhanSo& b);
 friend bool operator<(const PhanSo& a, const PhanSo& b);
 friend bool operator>(const PhanSo& a, const PhanSo& b);
};

// --- ĐỊNH NGHĨA HÀM TỰ DO ---

// Toán tử Bằng
bool operator==(const PhanSo& a, const PhanSo& b) {
 // Nhờ đã rút gọn ngầm, chỉ cần so sánh trực tiếp!
 return (a.tuSo == b.tuSo) && (a.mauSo == b.mauSo);
}

// Toán tử Nhỏ hơn (Nhân chéo)
bool operator<(const PhanSo& a, const PhanSo& b) {
 return (a.tuSo * b.mauSo) < (b.tuSo * a.mauSo);
}

// Toán tử Lớn hơn
bool operator>(const PhanSo& a, const PhanSo& b) {
 return (a.tuSo * b.mauSo) > (b.tuSo * a.mauSo);
}

// Mẹo của Senior: Đã có == và <, ta có thể suy ra các phép còn lại 
// mà không cần chọc vào private nữa (Không cần làm friend)
bool operator!=(const PhanSo& a, const PhanSo& b) { return !(a == b); }
bool operator<=(const PhanSo& a, const PhanSo& b) { return (a < b) || (a == b); }
bool operator>=(const PhanSo& a, const PhanSo& b) { return !(a < b); }

// ------------------------------------------------

int main() {
 cout << "--- HE THONG SO SANH PHAN SO ---\n";

 PhanSo ps1(2, 4); // Rút gọn thành 1/2
 PhanSo ps2(1, 2); // 1/2
 PhanSo ps3(3, 4); // 3/4

 cout << "ps1: " << ps1 << " | ps2: " << ps2 << " | ps3: " << ps3 << "\n\n";

 // 1. So sánh 2 Object
 if (ps1 == ps2) cout << "[X] ps1 bang ps2!\n";
 if (ps1 < ps3) cout << "[X] ps1 nho hon ps3!\n";

 // 2. So sánh Object với số nguyên (Tính giao hoán nhờ Friend)
 if (ps1 < 1) cout << "[X] ps1 nho hon 1!\n";
 
 // Số nguyên nằm bên trái vẫn chạy mượt mà!
 if (1 > ps1) cout << "[X] 1 lon hon ps1!\n"; 

 return 0;
}

Nhận xét: Kỹ thuật "tái sử dụng" logic ở nhóm toán tử !=, <=, >= là một thói quen cực tốt của các Kỹ sư dạn dày kinh nghiệm. Nó giúp bạn giảm thiểu code lặp lại (DRY - Don't Repeat Yourself) và hạn chế bug nếu sau này logic so sánh lõi bị thay đổi.

Tạm kết & Gợi mở

Chúc mừng anh em! Với mảnh ghép So sánh này, Class PhanSo của chúng ta đã chính thức hoàn thiện 100%. Nó mạnh mẽ, an toàn, thông minh và hòa nhập hoàn toàn vào hệ sinh thái chuẩn của C++.

Hành trình từ Bài 1 đến Bài 34, chúng ta đã xoay sở, nhào nặn và tối ưu hóa MỘT CLASS DUY NHẤT.

Nhưng trong một hệ thống phần mềm thực tế, bạn hiếm khi làm việc với 1 Class đơn độc. Hãy tưởng tượng bạn đang code một con Game. Bạn có Class QuaiVat (có máu, tốc chạy, hàm di chuyển). Rồi Sếp yêu cầu bạn tạo thêm Class BossLửa, Class BossNước. Chẳng lẽ bạn lại mở file mới ra và copy-paste lại đống code di chuyển, máu me của QuaiVat sang cho bọn Boss?

Việc copy-paste code là tội ác tày trời trong lập trình. Để giải quyết bài toán "Tái sử dụng cấp độ hệ thống", OOP mang đến cho chúng ta một khái niệm vĩ đại: Kế thừa (Inheritance).

Hẹn gặp lại anh em ở Bài 35: Đặc tính cơ bản của kế thừa đơn - Sự truyền ngôi của các Class! Đừng quên lưu lại project Phân số này làm hành trang đi phỏng vấn nhé!

📚 Nguồn: Viblo

Chia sẻ bài viết

Cần tư vấn?

Liên hệ với chúng tôi để được hỗ trợ

Liên hệ ngay

Bài viết liên quan

🤖 Building Social Games with AI — The Practitioner's Guide 📖
14/05/2026

🤖 Building Social Games with AI — The Practitioner's Guide 📖

> A comprehensive, opinionated, actionable guide for **using AI to build, ship, and operate social games** in the lineage covered by [🌾 The Social Games Playbook 🎮](https://dev.to/truongpx396/th...

Đọc thêm
qs88nl5001
14/05/2026

qs88nl5001

qs88 mang đến sân chơi giải trí trực tuyến chuyên nghiệp với hệ thống vận hành ổn định cùng tốc độ xử lý nhanh chóng. Người tham gia dễ dàng tiếp cận h...

Đọc thêm
Claude đã giúp lưu lượng truy cập website của tôi tăng gấp đôi như thế nào ?
14/05/2026

Claude đã giúp lưu lượng truy cập website của tôi tăng gấp đôi như thế nào ?

> Bài viết này được tổng hợp và diễn giải lại từ bài gốc ["Claude is Doubling My Website Traffic"](https://nick-nolan.medium.com/claude-is-doubling-my-website-traffic-1a26a793b...

Đọc thêm

Bắt đầu dự án của bạn

Hãy để Flash Dev đồng hành cùng bạn

Liên hệ ngay