26. Sử dụng ngữ nghĩa tự nhiên cho nạp chồng toán tử

Estimated reading: 5 minutes 284 views

Tóm tắt

Lập trình viên ghét những điều bất ngờ: Chỉ nên nạp chồng toán tử nếu thực sự cần thiết, và hãy giữ nguyên ngữ nghĩa tự nhiên của toán tử đó. Nếu điều này khó thực hiện, rất có thể bạn đang lạm dụng việc nạp chồng toán tử.

Thảo luận

Dù ai cũng sẽ đồng ý (chúng tôi hy vọng vậy) rằng bạn không nên thực hiện phép trừ trong phần hiện thực của operator+, thì vẫn có nhiều trường hợp tinh vi hơn.

Ví dụ:

  • Toán tử operator* trong lớp Tensor của bạn có ý nghĩa là tích vô hướng (scalar product) hay tích vector (vector product)?

  • operator+= (Tensor& t, unsigned u) có cộng u vào từng phần tử trong t, hay là thay đổi kích thước của t?

Trong những trường hợp mơ hồ hoặc dễ gây hiểu nhầm như vậy, hãy ưu tiên dùng hàm có tên rõ ràng thay vì sử dụng toán tử, vốn có thể khiến mã trở nên bí hiểm.

Đối với các kiểu giá trị (value types) (nhưng không phải tất cả các loại, xem Mục 32):

“Khi không chắc, hãy làm như cách mà int làm.” — [Meyers96]

Bắt chước hành vi và mối quan hệ giữa các toán tử đối với kiểu built-in (như int, float) giúp bạn tránh gây bất ngờ cho người dùng.

Nếu ngữ nghĩa mà bạn chọn cho toán tử có thể khiến người đọc nhíu mày hoặc nghi ngờ thì có lẽ bạn không nên nạp chồng toán tử.

Lập trình viên thường kỳ vọng toán tử đi theo nhóm. Nếu biểu thức a @ b hợp lệ đối với một toán tử @ mà bạn định nghĩa (có thể sau khi ép kiểu), hãy tự hỏi:

  • Liệu người dùng có thể viết b @ a mà không bị bất ngờ không?

  • Họ có thể viết a @= b không? (xem Mục 27)

  • Nếu toán tử đó có phép nghịch đảo (ví dụ: + và -, hoặc * và /), thì bạn có hỗ trợ cả hai không?

Hàm có tên rõ ràng ít khi mang theo kỳ vọng về các mối quan hệ toán học như vậy, nên nếu ngữ nghĩa không hoàn toàn rõ ràng, hãy ưu tiên dùng hàm để mã dễ hiểu hơn.

Ngoại lệ

Một số thư viện chuyên biệt cao (ví dụ: bộ tạo parser, hoặc thư viện biểu thức chính quy (regular expression engine)) định nghĩa những quy ước toán tử riêng biệt rất khác với ý nghĩa thông thường trong C++. (Ví dụ: một thư viện biểu thức chính quy có thể dùng operator* để biểu diễn “không hoặc nhiều hơn một lần” (“zero or more”))

 Trong trường hợp đó, tốt hơn là tìm một giải pháp thay thế cho việc nạp chồng toán tử bất thường. Ví dụ: chuẩn [C++TR104] đề xuất sử dụng chuỗi strings để biểu diễn biểu thức chính quy, để có thể dùng * theo nghĩa tự nhiên mà không cần nạp chồng toán tử.

Tuy nhiên, nếu sau khi suy nghĩ cẩn trọng bạn vẫn chọn dùng nạp chồng toán tử, hãy đảm bảo rằng bạn:

  • Xây dựng một khung quy tắc nhất quán, rõ ràng cho ngữ nghĩa các toán tử bạn dùng;

  • Tránh gây xung đột với ngữ nghĩa của các toán tử built-in.

Tham khảo

[Cline99] §23.02-06 • [C++TR104] §7 • [DewhurstO3] §85-86 • [Koenig97] §4 • [Lakos96] §9.1.1 • [Meyers96] §6 • [StroustrupOO] §11.1 • [SutterOOl §41

Link 

Leave a Comment

Chia sẻ:

26. Sử dụng ngữ nghĩa tự nhiên cho nạp chồng toán tử

Or copy link

CONTENTS