+1

[C++ OOP Thực Chiến] Bài 24: Giới thiệu Nạp chồng toán tử (Operator Overloading) - Phép thuật thao túng C++

Chào anh em! Ở [Bài 23], chúng ta đã giải quyết bài toán cộng phân số bằng cách gọi hàm: PhanSo tong = ToanHoc::cong(ps1, ps2);

Tuy nhiên, đối với một Kỹ sư phần mềm, việc phải gõ đi gõ lại chữ cong(), tru(), nhan(), chia() khiến mã nguồn trở nên dài dòng và vô cùng khó đọc khi biểu thức phức tạp lên. Giả sử bạn muốn tính (a + b) * c, nếu dùng hàm thì code sẽ thành: ToanHoc::nhan(ToanHoc::cong(a, b), c); -> Đọc xong lú luôn!

Làm sao để chúng ta có thể gõ trực tiếp PhanSo ketQua = (ps1 + ps2) * ps3; y như kiểu int hay float?

Đó là lúc chúng ta kích hoạt Nạp chồng toán tử (Operator Overloading).

1. Nạp chồng toán tử là gì?

Từ "Overloading" (Nạp chồng) chúng ta đã gặp ở Bài 21 khi viết nhiều hàm Constructor cùng tên nhưng khác tham số.

Nạp chồng toán tử cũng tương tự. Các toán tử trong C++ như +, -, *, /, ==, <, > thực chất cũng chỉ là... những cái Hàm được viết tắt! Mặc định, C++ chỉ biết cách dùng dấu + cho các kiểu dữ liệu gốc (số nguyên, số thực). Khi bạn đặt dấu + giữa hai Object PhanSo, C++ sẽ báo lỗi vì nó không biết phải cộng tử số với mẫu số như thế nào.

Việc của bạn là "dạy" cho C++ biết: "Ê C++, khi tao đặt dấu + ở giữa hai cái Object PhanSo, mày hãy chạy đoạn code logic này cho tao!".

2. Cú pháp cơ bản của "Phép thuật"

Để nạp chồng một toán tử, bạn cần viết một hàm đặc biệt sử dụng từ khóa operator theo sau là ký hiệu toán tử bạn muốn định nghĩa lại.

Cú pháp chung:

KiểuTrảVề operator KýHiệu (DanhSáchThamSố) {
    // Logic xử lý của bạn
}

Ví dụ: PhanSo operator+ (PhanSo a, PhanSo b)

Nhờ khai báo này, mỗi khi trình biên dịch C++ nhìn thấy dòng code ps1 + ps2, nó sẽ tự động biến hình (dịch ngầm) thành lời gọi hàm: operator+(ps1, ps2). Khá là vi diệu đúng không?

3. Ba "Quy tắc thép" không thể phá vỡ

Dù C++ cho bạn rất nhiều quyền năng, nhưng bạn không được phép làm "loạn" hệ thống. Khi dùng Operator Overloading, phải nhớ kỹ:

  1. Không được đẻ ra toán tử mới: Bạn chỉ có thể định nghĩa lại các toán tử ĐÃ CÓ SẴN của C++. Bạn không thể tự chế ra toán tử ** (phép mũ) hay <> được.
  2. Không làm thay đổi thứ tự ưu tiên (Precedence): "Nhân chia trước, cộng trừ sau" là luật bất di bất dịch. Nếu bạn nạp chồng dấu * và dấu +, C++ vẫn sẽ ưu tiên tính dấu * trước trong một biểu thức dài, dù bạn có muốn hay không.
  3. Những toán tử "bất khả xâm phạm": Bạn KHÔNG THỂ nạp chồng các toán tử sau:
  • Toán tử phân giải phạm vi ::
  • Toán tử truy cập thành viên .
  • Toán tử ba ngôi ?:
  • Toán tử sizeof

4. Phân loại toán tử để "chiến đấu"

Để làm chủ kỹ năng này, anh em cần phân biệt được 2 nhóm toán tử chính:

  • Toán tử 1 ngôi (Unary Operator): Chỉ tác động lên 1 Object duy nhất. Ví dụ: Dấu âm (-ps1), phép tăng/giảm (++ps1,ps1--), phép phủ định (!ps1).
  • Toán tử 2 ngôi (Binary Operator): Cần 2 Object để thực hiện. Ví dụ: Cộng (ps1 + ps2), so sánh (ps1 == ps2).

Và để code các toán tử này, bạn có thể viết nó dưới dạng Member Function (Phương thức nằm TRONG Class) hoặc Friend Function (Hàm bạn nằm NGOÀI Class). Mỗi cách có một cái hay và cái dở riêng.

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

Tuyệt vời! Chúng ta đã nắm được lý thuyết nền tảng về Nạp chồng toán tử. Đây là bước ngoặt biến Class của bạn từ một "cái hộp chứa data" thành một kiểu dữ liệu xịn xò không kém gì hàng "chính hãng" của C++.

Trước khi nhảy vào đánh con Boss khó nhằn là Phép cộng 2 ngôi (như ps1 + ps2), chúng ta hãy khởi động bằng một toán tử dễ thở hơn: Toán tử 1 ngôi.

Giả sử bạn có phân số 1/2. Làm sao để khi bạn gõ -ps1, hệ thống tự động trả về -1/2? Và làm sao để code logic này ngay bên trong Class (dùng Member Function) cùng với sự trợ giúp của con trỏ this?

Hẹn gặp lại anh em ở Bài 25: Nạp chồng Toán tử số đối (Unary Minus) bằng Member Function. Hãy mở sẵn file Class PhanSo của bài trước để chuẩn bị gõ phím nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí