Nạp chồng toán tử trong C#

Operator Overloading là Nạp chồng toán tử. Bạn có thể tái định nghĩa hoặc nạp chồng hầu hết các toán tử có sẵn trong C#. Vì thế, một lập trình viên có thể sử dụng các toán tử với các kiểu tự định nghĩa (user-defined).

Các toán tử được nạp chồng trong C# là các hàm với các tên đặc biệt: biểu tượng cho toán tử đang được định nghĩa sẽ có từ khóa operator ngay phía sau. Tương tự như bất kỳ hàm nào khác, một toán tử được nạp chồng có một kiểu trả về và một danh sách tham số.

Ví dụ, bạn xét hàm sau:

public static Hop operator+ (Hop b, Hop c)
{
 Hop hopA = new Hop();
 hopA.chieu_dai = b.chieu_dai + c.chieu_dai;
 hopA.chieu_rong = b.chieu_rong + c.chieu_rong;
 hopA.chieu_cao = b.chieu_cao + c.chieu_cao;
 return hopA;
}

Hàm trên triển khai toán tử cộng (+) cho một lớp Hop tự định nghĩa (user-defined). Nó cộng các thuộc tính của hai đối tượng Hop và trả về đối tượng kết quả Hop.

Triển khai Nạp chồng toán tử trong C#

Ví dụ dưới đây minh họa cách triển khai nạp chồng toán tử trong C#: tạo hai lớp có tên lần lượt là HopThuTinh như sau:

using System;

namespace VdNapChongToanTu {
   // Lớp Hop chứa các thuộc tính và phương thức.
   class Hop {
      private double chieu_dai;   // Chiều dài của hộp
      private double chieu_rong;  // Chiều rộng của hộp
      private double chieu_cao;   // Chiều cao của hộp

      public double tinhTheTich() {
         return chieu_dai * chieu_rong * chieu_cao;
      }
      public void ganChieuDai( double dai ) {
         chieu_dai = dai;
      }
      public void ganChieuRong( double rong ) {
         chieu_rong = rong;
      }
      public void ganChieuCao( double cao ) {
         chieu_cao = cao;
      }
      
      // Nạp chồng toán tử + để cộng hai object Hop
      public static Hop operator+ (Hop b, Hop c) {
         Hop hopA = new Hop();
         hopA.chieu_dai = b.chieu_dai + c.chieu_dai;
         hopA.chieu_rong = b.chieu_rong + c.chieu_rong;
         hopA.chieu_cao = b.chieu_cao + c.chieu_cao;
         return hopA;
      }
   }
   // Lớp ThuTinh chứa phương thức main() để thao tác trên đối tượng Hop.
   class ThuTinh {
      static void Main(string[] args) {
         Hop Hop1 = new Hop();   // Khai báo Hop1 thuộc loại Hop
         Hop Hop2 = new Hop();   // Khai báo Hop2 thuộc loại Hop
         Hop Hop3 = new Hop();   // Khai báo Hop3 thuộc loại Hop
         double TheTich = 0.0;   // Lưu thể tích Hop ở đây

         // Thông số của Hop1
         Hop1.ganChieuDai(6.0);
         Hop1.ganChieuRong(7.0);
         Hop1.ganChieuCao(5.0);

         // Thông số của Hop2
         Hop2.ganChieuDai(12.0);
         Hop2.ganChieuRong(13.0);
         Hop2.ganChieuCao(10.0);

         // Thể tích của Hop1
         TheTich = Hop1.tinhTheTich();
         Console.WriteLine("Thể tích của Hop1: {0}", TheTich);

         // Thể tích của Hop2
         TheTich = Hop2.tinhTheTich();
         Console.WriteLine("Thể tích của Hop2: {0}", TheTich);

         // Cộng 2 thể tích như bên dưới:
         Hop3 = Hop1 + Hop2;

         // Thể tích của Hop3
         TheTich = Hop3.tinhTheTich();
         Console.WriteLine("Thể tích của Hop3: {0}", TheTich);
         Console.ReadKey();
      }
   }
}

Hãy dùng lệnh Console.ReadKey(); để nhìn kết quả một cách rõ ràng hơn.

Biên dịch và chạy chương trình C# trên sẽ cho kết quả sau:

Th tích ca Hop1: 210
Th tích ca Hop2: 1560
Th tích ca Hop3: 5400

Toán tử có thể nạp chồng và không thể nạp chồng trong C#

Bảng dưới miêu tả các toán tử có thể nạp chồng trong C#:

Toán tử Mô tả
+, -, !, ~, ++, — Những toán tử một ngôi này nhận một toán hạng và có thể được nạp chồng.
+, -, *, /, % Những toán tử nhị phân này nhận một toán hạng và có thể được nạp chồng.
=, !=, <, >, <=, >= Các toán tử so sánh có thể được nạp chồng.
&&, || Các toán tử logic điều kiện không thể được nạp chồng một cách trực tiếp.
+=, -=, *=, /=, %= Các toán tử gán không thể được nạp chồng.
=, ., ?:, ->, new, is, sizeof, typeof Các toán tử này không thể được nạp chồng.

Ví dụ

Từ những nội dung đã thảo luận bên trên, chúng ta kế thừa ví dụ trên và nạp chồng thêm một số toán tử trong C#: ở trên chúng ta đã tạo hai lớp Hop, ThuTinh, bây giờ chúng ta sửa lại code của mỗi lớp như sau:

using System;

namespace VdNapChongToanTu {
   // Lớp Hop chứa các thuộc tính và phương thức.
   class Hop {
      private double chieu_dai;   // Chiều dài của hộp
      private double chieu_rong;  // Chiều rộng của hộp
      private double chieu_cao;   // Chiều cao của hộp

      public double tinhTheTich() {
         return chieu_dai * chieu_rong * chieu_cao;
      }
      public void ganChieuDai( double dai ) {
         chieu_dai = dai;
      }
      public void ganChieuRong( double rong ) {
         chieu_rong = rong;
      }
      public void ganChieuCao( double cao ) {
         chieu_cao = cao;
      }
      
      // Nạp chồng toán tử + để cộng hai object Hop
      public static Hop operator+ (Hop b, Hop c) {
         Hop hopA = new Hop();
         hopA.chieu_dai = b.chieu_dai + c.chieu_dai;
         hopA.chieu_rong = b.chieu_rong + c.chieu_rong;
         hopA.chieu_cao = b.chieu_cao + c.chieu_cao;
         return hopA;
      }   

      public static bool operator == (Hop lhs, Hop rhs) {
         bool status = false;
         if (lhs.chieu_dai == rhs.chieu_dai && lhs.chieu_cao == rhs.chieu_cao 
            && lhs.chieu_rong == rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public static bool operator !=(Hop lhs, Hop rhs) {
         bool status = false;
         
         if (lhs.chieu_dai != rhs.chieu_dai || lhs.chieu_cao != rhs.chieu_cao || 
            lhs.chieu_rong != rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public static bool operator <(Hop lhs, Hop rhs) {
         bool status = false;
         
         if (lhs.chieu_dai < rhs.chieu_dai && lhs.chieu_cao < rhs.chieu_cao 
            && lhs.chieu_rong < rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public static bool operator >(Hop lhs, Hop rhs) {
         bool status = false;
         
         if (lhs.chieu_dai > rhs.chieu_dai && lhs.chieu_cao > 
            rhs.chieu_cao && lhs.chieu_rong > rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public static bool operator <=(Hop lhs, Hop rhs) {
         bool status = false;
         
         if (lhs.chieu_dai <= rhs.chieu_dai && lhs.chieu_cao 
            <= rhs.chieu_cao && lhs.chieu_rong <= rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public static bool operator >=(Hop lhs, Hop rhs) {
         bool status = false;
         
         if (lhs.chieu_dai >= rhs.chieu_dai && lhs.chieu_cao 
            >= rhs.chieu_cao && lhs.chieu_rong >= rhs.chieu_rong) {
            
            status = true;
         }
         return status;
      }
      public override string ToString() {
         return String.Format("({0}, {1}, {2})", chieu_dai, chieu_rong, chieu_cao);
      }
   }
    // Lớp ThuTinh chứa phương thức main() để thao tác trên đối tượng Hop.
   class ThuTinh {
      static void Main(string[] args) {
         Hop Hop1 = new Hop();   // Khai báo Hop1 thuộc loại Hop
         Hop Hop2 = new Hop();   // Khai báo Hop2 thuộc loại Hop
         Hop Hop3 = new Hop();   // Khai báo Hop3 thuộc loại Hop
         Hop Hop4 = new Hop();   // Khai báo Hop4 thuộc loại Hop
         double TheTich = 0.0;   // Lưu thể tích Hop ở đây

         // Thông số của Hop1
         Hop1.ganChieuDai(6.0);
         Hop1.ganChieuRong(7.0);
         Hop1.ganChieuCao(5.0);

         // Thông số của Hop2
         Hop2.ganChieuDai(12.0);
         Hop2.ganChieuRong(13.0);
         Hop2.ganChieuCao(10.0);
         
         // Hiển thị các hộp sử dụng nạp chồng ToString():
         Console.WriteLine("Hop1: {0}", Hop1.ToString());
         Console.WriteLine("Hop2: {0}", Hop2.ToString());
         
         // Thể tích Hop1
         TheTich = Hop1.tinhTheTich();
         Console.WriteLine("Thể tích Hop1 : {0}", TheTich);
         
         // Thể tích Hop2
         TheTich = Hop2.tinhTheTich();
         Console.WriteLine("Thể tích Hop2 : {0}", TheTich);
         
         // Cộng 2 đối tượng như bên dưới:
         Hop3 = Hop1 + Hop2;
         Console.WriteLine("Hop3: {0}", Hop3.ToString());
         
         // Thể tích Hop3
         TheTich = Hop3.tinhTheTich();
         Console.WriteLine("Thể tích Hop3 : {0}", TheTich);
         
         //So sánh các hộp
         if (Hop1 > Hop2)
            Console.WriteLine("Hop1 lớn hơn Hop2");
         else
            Console.WriteLine("Hop1 không lớn hơn Hop2");
         
         if (Hop1 < Hop2)
            Console.WriteLine("Hop1 nhỏ hơn Hop2");
         else
            Console.WriteLine("Hop1 không nhỏ hơn Hop2");
         
         if (Hop1 >= Hop2)
            Console.WriteLine("Hop1 lớn hơn hoặc bằng Hop2");
         else
            Console.WriteLine("Hop1 không lớn hơn hoặc bằng Hop2");
         
         if (Hop1 <= Hop2)
            Console.WriteLine("Hop1 nhỏ hơn hoặc bằng Hop2");
         else
            Console.WriteLine("Hop1 không nhỏ hơn hoặc bằng Hop2");
         
         if (Hop1 != Hop2)
            Console.WriteLine("Hop1 không bằng Hop2");
         else
            Console.WriteLine("Hop1 không lớn hơn hoặc bằng Hop2");
         Hop4 = Hop3;
         
         if (Hop3 == Hop4)
            Console.WriteLine("Hop3 bằng Hop4");
         else
            Console.WriteLine("Hop3 không bằng Hop4");

         Console.ReadKey();
      }
   }
}

Biên dịch và chạy chương trình C# trên sẽ cho kết quả sau:

Hop1: (6, 7, 5)
Hop2: (12, 13, 10)
Th tích Hop1 : 210
Th tích Hop2 : 1560
Hop3: (18, 20, 15)
Th tích Hop3 : 5400
Hop1 không ln hơn Hop2
Hop1 nh hơn Hop2
Hop1 không ln hơn hoc bng Hop2
Hop1 nh hơn hoc bng Hop2
Hop1 không bng Hop2
Hop3 bng Hop4