Nạp chồng toán tử
Tính năng hiện đại của ngôn ngữ Delphi
Tính năng hiện đại của ngôn ngữ Delphi
Nạp chồng toán tử (operator overloading) là một kĩ thuật lập trình hiện đại, nó cho phép chúng ta có thể thực hiện phép tính với các class (hoặc record) như đối với các biến thông thường.
Ví dụ, có hai object của class TPhanSo là PS1 và PS2. Class TPhanSo gồm 2 trường và một thuộc tính Print để in ra màn hình.
type
TPhanSo = class
TuSo: Integer;
MauSo: Integer;
procedure Print;
end;
procedure TPhanSo.Print;
begin
writeln(Self.TuSo, ' / ', Self.MauSo);
end;
var
PS1, PS2, PSTong: TPhanSo;
begin
PS1 := TPhanSo.Create;
PS2 := TPhanSo.Create;
PSTong := TPhanSo.Create;
try
...
finally
PS1.Free;
PS2.Free;
PS3.Free;
end;
end;
Chỗ ... mình muốn tính tổng hai phân số trên và lưu vào phân số PSTong. Bạn sẽ làm như thế nào.
Delphi cung cấp một cách thức dễ dàng để tính toán với các dữ liệu có cấu trúc như class hoặc record, gọi là operator overloading (nạp chồng toán tử). Với operation overloading, để tính tổng hai phân số PS1 và PS2 ở trên chỉ cần viết
PS3 := PS1 + PS2;
tương tự như cộng hai số vậy.
Delphi operator overloading được triển khai như là các method bên trong record hoặc class.
Nói chung, trong delphi, operator overloading hỗ trợ khá nhiều phép tính toán, dưới đây là danh sách một số toán tử quan trọng:
Cộng, trừ, nhân, chia: Có cấu trúc method là Add(a, b: Type): Type; với Add là tên mặc định của toán tử. Cộng (Add), Trừ (Subtract), Nhân (Multiply), Chia (Divide). Thao tác này nhận vào hai giá trị, trả về một giá trị (giống như phép cộng nhận vào 2 số và trả về 1 số vậy đó)
Phép so sánh: Có cấu trúc method là Equal(a, b: Type): boolean; với Equal là tên toán tử. Equal (bằng), NotEqual (không bằng), GreaterThan (lớn hơn), LessThan (nhỏ hơn), GreaterThanOrEqual (lớn hơn hoặc bằng), LessThanOrEqual (nhỏ hơn hoặc bằng). Thao tác này nhận vào 2 giá trị, trả về biến boolean là so sánh hai giá trị đó.
Phép Implicit (còn có phép tương đương là Explicit nhưng mình không biết sự khác nhau giữa 2 cái này). Dùng để chuyển đổi kiểu, có cấu trúc method như sau Implicit(a: type): type; Ví dụ, gán một record bằng 10 thì method Implicit sẽ là Implicit(a: Integer): TRecord;
Nói chung phần này khá trừu tượng, nên bạn cố gắng xem code và hiểu vậy
Mình sẽ lấy ví dụ phân số ở trên, nạp chồng 4 toán tử: cộng, so sánh bằng, lớn hơn và implicit. Mình sẽ sử dụng record thay cho class để code gọn hơn, vì record tương tự class và không cần khởi tạo object chi cho rắc rối.
type
TPhanSo = record
TuSo: Integer;
MauSo: Integer;
class operator Implicit(s: string): TPhanSo;
class operator Equal(a, b: TPhanSo): boolean;
class operator GreaterThan(a, b: TPhanSo): boolean;
class operator Add(a, b: TPhanSo): TPhanSo;
end;
class operator TPhanSo.Implicit(s: string): TPhanSo;
var
SeparatorPos: Integer;
begin
// Phân tích một string dạng 2/3 vào trường TuSo và MauSo
// Không an toàn vì chưa kiểm tra đúng là số hay không, nhưng mà ví dụ nên tạm chấp nhận
SeparatorPos := Pos('/', s);
Result.TuSo := StrToInt(Copy(s, 1, SeparatorPos - 1));
Result.MauSo := StrToInt(Copy(s, SeparatorPos + 1, Length(s) - SeparatorPos));
end;
class operator TPhanSo.Equal(a, b: TPhanSo): boolean;
begin
if a.TuSo * b.MauSo = a.MauSo * b.TuSo then
Result := true
else
Result := false;
// Hoặc ngắn hơn: Result := a.TuSo * b.MauSo = a.MauSo * b.TuSo;
end;
class operation TPhanSo.GreaterThan(a, b: TPhanSo): boolean;
begin
if a.TuSo * b.MauSo > a.MauSo * b.TuSo then
Result := true
else
Result := false;
end;
class operator TPhanSo.Add(a, b: TPhanSo): TPhanSo;
begin
Result.TuSo := a.TuSo * b.MauSo + a.MauSo * b.TuSo;
Result.MauSo := a.MauSo * b.MauSo;
end;
var
PS1, PS2, PS3: TPhanSo;
begin
// Chuyển đổi kiểu implicit từ string sang TPhanSo
// Tương đương với method PS1 := TPhanSo.Implicit('2/3');
PS1 := '2/3';
PS2 := '1/2';
// So sánh (lớn hơn)
if PS1 > PS2 then
writeln('PS1 lon hon PS2')
else
writeln('PS1 nho hon hoac bang PS2');
// Cộng
PS3 := PS1 + PS2;
writeln(PS3.TuSo, ' / ', PS3.MauSo);
readln
end;
Khi sử dụng operator overloading, nếu kiểu trả về là kiểu có cấu trúc thì trong thân method, bạn cần sử dụng biến trả về Result thay cho Self.
Bạn có thể nâng cấp record TPhanSo trên bằng cách mở rộng nó ra nhiều operator nữa.
Liên kết bài đọc thêm nâng cao: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Operator_Overloading_(Delphi)