Chương 6 Nạp chồng toán tử

Một phần của tài liệu Phát triển ứng dụng cơ sở dữ liệu với c và net framework (Trang 44 - 48)

Mục tiêu thiết kế của C# là kiểu người dùng định nghĩa (lớp) phải được đối xử

như các kiểu định sẵn. Ví dụ, chúng ta muốn định nghĩa lớp phân số (Fraction) thì các chức năng như cộng, trừ, nhân,… phân số là điều tất yếu phải có. Để làm được việc đó ta định nghĩa các phương thức: cộng, nhân,… khi đó, ta phải viết là:

Phân_số tổng = số_thứ_nhất.cộng(số_thứ_hai);

Cách này hơi gượng ép và không thể hiện hết ý nghĩa. Điểu ta muốn là viết thành:

Phân_số tổng = số_thứ_nhất + số_thứ_hai; để làm được điều này ta dùng từ

khoá operator để thể hiện.

6.1. Cách dùng từ khoá operator

Trong C#, các toán tử là các phương thức tĩnh, kết quả trả về của nó là giá trị

biểu diễn kết quả của một phép toán và các tham số là các toán hạng. Khi ta tạo một toán tử cho một lớp ta nói là ta nạp chồng toán tử, nạp chồng toán tử cũng giống như bất kỳ việc nạp chồng các phương thức nào khác. Ví dụ nạp chồng toán tử cộng (+) ta viết như sau:

public static Fraction operator+ (Fraction lhs, Fraction rhs)

Nó chuyển tham số lhs về phía trái toán tử và rhs về phía phải của toán tử. Cú pháp C# cho phép nạp chồng toán tử thông qua việc dùng từ khoá operator.

6.2. Cách hổ trợ các ngôn ngữ .Net khác

C# cung cấp khả năng nạp chồng toán tử cho lớp của ta, nói đúng ra là trong Common Language Specification (CLS). Những ngôn ngữ khác như VB.Net có thể

không hổ trợ nạp chồng toán tử, do đó, điều quan trọng là ta cũng cung cấp các phương thức hổ trợ kèm theo các toán tửđể có thể thực hiện được ở các môi trường khác. Do đó, khi ta nạp chồng toán tử cộng (+) thì ta cũng nên cung cấp thêm phương thức add() với cùng ý nghĩa.

6.3. Sự hữu ích của các toán tử

Các toán tử được nạp chồng có thể giúp cho đoạn mã nguồn của ta dễ nhìn hơn, dễ quản lý và trong sáng hơn. Tuy nhiên nếu ta quá lạm dụng đưa vào các toán tử quá mới hay quá riêng sẽ làm cho chương trình khó sử dụng các toán tử này mà

đôi khi còn có các nhầm lẫn vô vị nữa.

6.4. Các toán tử logic hai ngôi

Các toán tử khá phổ biến là toán tử (==) so sánh bằng giữ hai đối tượng, (!=) so sánh không bằng, (<) so sánh nhỏ hơn, (>) so sánh lớn hơn, (<=, >=) tương ứng nhỏ hơn hay bằng và lớn hơn hay bằng là các toán tử phải có cặp toán hạng hay gọi là các toán tử hai ngôi.

6.5. Toán tử so sánh bằng

Nếu ta nạp chồng toán tử so sánh bằng (==), ta cũng nên cung cấp phương thức ảo Equals() bởi object và hướng chức năng này đến toán tử bằng. Điều này cho phép lớp của ta đa hình và cung cấp khả năng hữu ích cho các ngôn ngữ .Net khác.

Phương thức Equals() được khai báo như sau: public override bool Equals(object o)

Bằng cách nạp chồng phương thức này, ta cho phép lớp Fraction đa hình với tất cả các đối tượng khác. Nội dung của Equals() ta cần phải đảm bảo rằng có sự so sánh với đối tượng Fraction khác. Ta viết như sau:

public override bool Equals(object o) {

if (! (o is Fraction) ) {

return false; }

return this == (Fraction) o; }

Toán tử is được dùng để kiểm tra kiểu đang chạy có phù hợp với toán hạng yêu cầu không. Do đó, o is Fraction là đúng nếu o có kiểu là Fraction.

6.6. Toán tử chuyển đổi kiểu (ép kiểu)

Trong C# cũng như C++ hay Java, khi ta chuyển từ kiểu thấp hơn (kích thước nhỏ) lên kiểu cao hơn (kích thước lớn) thì việc chuyển đổi này luôn thành công nhưng khi chuyển từ kiểu cao xuống kiểu thấp có thể ta sẽ mất thông tin. Ví dụ ta chuyển từint thành long luôn luôn thành công nhưng khi chuyển ngược lại từ long

thành int thì có thể tràn số không như ý của ta. Do đó khi chuyển từ kiểu cao xuống thấp ta phải chuyển tường minh.

Cũng vậy muốn chuyển từint thành kiểu Fraction luôn thành công, ta dùng từ

khoá implicit để biểu thị toán tử kiểu này. Nhưng khi chuyển từ kiểu Fraction có thể sẽ mất thông tin do vậy ta dùng từ khoá explicit để biểu thị toán tử chuyển đổi tường minh.

Ví dụ 6-1 Minh hoạ chuyển đổi ngầm định và tường minh

using System;

public class Fraction {

public Fraction(int numerator, int denominator) {

Console.WriteLine("In Fraction Constructor(int, int)"); this.numerator=numerator;

this.denominator=denominator; }

public Fraction(int wholeNumber) {

Console.WriteLine("In Fraction Constructor(int)"); numerator = wholeNumber;

denominator = 1; }

public static implicit operator Fraction(int theInt)

{

System.Console.WriteLine("In implicit conversion to Fraction"); return new Fraction(theInt);

}

public static explicit operator int(Fraction theFraction)

{

System.Console.WriteLine("In explicit conversion to int"); return theFraction.numerator / theFraction.denominator; }

public static bool operator==(Fraction lhs, Fraction rhs) {

Console.WriteLine("In operator ==");

if (lhs.denominator == rhs.denominator && lhs.numerator == rhs.numerator) {

return true; }

// code here to handle unlike fractions return false;

}

public static bool operator !=(Fraction lhs, Fraction rhs) {

Console.WriteLine("In operator !="); return !(lhs==rhs);

}

public override bool Equals(object o) {

Console.WriteLine("In method Equals"); if (! (o is Fraction) )

{

return false; }

return this == (Fraction) o; }

public static Fraction operator+(Fraction lhs, Fraction rhs) {

Console.WriteLine("In operator+"); if (lhs.denominator == rhs.denominator) {

return new Fraction(lhs.numerator+rhs.numerator, lhs.denominator);

// simplistic solution for unlike fractions // 1/2 + 3/4 == (1*4) + (3*2) / (2*4) == 10/8

int firstProduct = lhs.numerator * rhs.denominator; int secondProduct = rhs.numerator * lhs.denominator;

return new Fraction(firstProduct + secondProduct, lhs.denominator * rhs.denominator);

}

public override string ToString( ) {

String s = numerator.ToString( ) + "/" + denominator.ToString( );

return s; }

private int numerator; private int denominator; }

public class Tester {

static void Main( ) {

//implicit conversion to Fraction Fraction f1 = new Fraction(3);

Console.WriteLine("f1: {0}", f1.ToString( )); Fraction f2 = new Fraction(2,4);

Console.WriteLine("f2: {0}", f2.ToString( )); Fraction f3 = f1 + f2;

Console.WriteLine("f1 + f2 = f3: {0}", f3.ToString( )); Fraction f4 = f3 + 5;

Console.WriteLine("f3 + 5 = f4: {0}", f4.ToString( )); Fraction f5 = new Fraction(2,4);

if (f5 == f2) {

Console.WriteLine("F5: {0} == F2: {1}", f5.ToString( ), f2.ToString( ));

}

int k = (int)f4; //explicit conversion to int

Console.WriteLine("int: F5 = {0}", k.ToString()); }

Một phần của tài liệu Phát triển ứng dụng cơ sở dữ liệu với c và net framework (Trang 44 - 48)

Tải bản đầy đủ (PDF)

(192 trang)