1. Trang chủ
  2. » Thể loại khác

...C06. Operator Overloading.pdf

7 129 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 7
Dung lượng 181,76 KB

Nội dung

• Bài giảng LTHĐTTrần Minh Châu ĐạiBài giảng LTHĐT, Trần Minh Châu, Đại học Công nghệ, ĐH Quốc gia HN• Bài giảng LTHĐT NguyễnNgọc Long ĐH• Bài giảng LTHĐT, Nguyễn Ngọc Long, ĐH KHTN TPHCMBài iả LTHĐTHỳ hLêTấ Tài ĐH• Bài giảng LTHĐT, Huỳnh Lê Tấn Tài, ĐH KHTN TPHCM• C++ How to Program, Dietel4/21/2007 Lập Trình Hướng Đối Tượng 2• Các toán tử cho phép ta sử dụng cú pháp toán học đối với các kiểu dữ liệu của C++ thay vì gọi hàm (tuy bản chất vẫn là gọi hàm).•Ví dụ thay a.set(b.cong(c)); bằng a = b + c;•Gần với kiểu trình bày mà con người quen dùng• Đơn giản hóa mã chương trình4/21/2007 Lập Trình Hướng Đối Tượng 3• C/C++ đãlàmsẵn các toán tử cho cácC/C++ đã làm sẵn các toán tử cho các kiểu cài sẵn (int, float…)• Đốivớicáckiểudữ liệungười dùng: C++• Đối với các kiểu dữ liệu người dùng: C++ cho phép định nghĩa các toán tử trên các kiểudữ liệungười dùng Æ overloadkiểu dữ liệu người dùng Æ overload4/21/2007 Lập Trình Hướng Đối Tượng 4 • Một toán tử có thể dùng cho nhiềukiểudữMột toán tử có thể dùng cho nhiều kiểu dữliệu.•Như vậy, ta có thể tạocáckiểudữ liệuNhư vậy, ta có thể tạo các kiểu dữ liệuđóng gói hoàn chỉnh (fullyencapsulated) để kết hợp với ngôn ngữ như các kiểu dữp ggliệu cài sẵn.•Ví dụ:SoPhuc z(1,3), z1(2,3.4), z2(5.1,4);z = z1 + z2;z = z1 + z2*z1 + SoPhuc(3,1);4/21/2007 Lập Trình Hướng Đối Tượng 5,;• Các toán tử được chia thành hai loại theo số toán hạng nó chấp nhận– Toán tử đơn nhận một toán hạng– Toán tử đôi nhận hai toán hạng–….• Các toán tử đơn lại được chia thành hai loạiạ ợ ạ– Toán tử trước đặt trước toán hạng– Toán tử sau đặt sau toán hạng4/21/2007 Lập Trình Hướng Đối Tượng 6•Một số toán tử đơn có thể được dùng làm cả toán tử trước và toán tử sau: ++,--,•Một số toán tử có thể được dùng làm cả toán tử đơnvàtoántử đôi: *toán tử đơn và toán tử đôi: • Toán tử chỉ mục ("[…]") là toán tử đôi, mặc dù một trong hai toán hạng nằm trongdù một trong hai toán hạng nằm trongngoặc: arg1[arg2]Cá từ kh á " " à "d l t " ũ đ• Các từ khoá "new" và "delete" cũng đượccoi là toán tử và có thể được định nghĩa lại4/21/2007 Lập Trình Hướng Đối Tượng 7>> <<4/21/2007 Lập Trình Hướng Đối Tượng 8 4/21/2007 Lập Trình Hướng Đối Tượng 9• Khai báo và định nghĩa toán tử thực chất khô khá ớiiệ kh i bá à đị hkhông khác với việc khai báo và định nghĩa một loại hàm bất kỳ nào khácSử d tê hà là " t @" h t á• Sử dụng tên hàm là "operator@" cho toán tử "@“: operator+Số l th ố t ikh ibá h th ộ• Số lượng tham số tại khai báo phụ thuộc hai yếu tố:• Toán tử là toán tử đơn hay đôi• Toán tử là toán tử đơn hay đôi• Toán tử được khai báo là hàm toàn cục hay phương thức của lớp4/21/2007 Lập Trình Hướng Đối Tượng 10aa@bb Î aa.operator@(bb) hoặc operator@(aa,bb)@ p@() ặ p@(,)@aa Î aa.operator@() hoặc operator@(aa)aa@ Î aa.operator@(int)hoặc operator@(aa,int)là phương thứccủalớp là hàm toàn cụclà phương thức của lớp là hàm toàn cục4/21/2007 Lập Trình Hướng Đối Tượng 11typedef int bool;itypedef int Item;const bool false = 0, true = 1;long USCLN(long x long y)long USCLN(long x, long y){long r;x = abs(x); y = abs(y);( ); y (y);if (x == 0 || y == 0) return 1;while ((r = x % y) != 0){x = y;y = r;}return y;4/21/2007 Lập Trình Hướng Đối Tượng 12return y;} lPhSclass PhanSo{long tu, mau;void UocLuoc();void UocLuoc();public:PhanSo(long t, long m) {Set(t,m);}void Set(long t, long m);odSet(ogt, og );long LayTu() const {return tu;}long LayMau() const {return mau;}PhanSo Cong(PhanSo b) const;PhanSo operator + (PhanSo b) const;PhanSo operator - () const {return PhanSo(-tu, mau);}}bool operator == (PhanSo b) const;bool operator != (PhanSo b) const; void Xuat() const4/21/2007 Lập Trình Hướng Đối Tượng 13void Xuat() const;};void PhanSo::UocLuoc() { long usc = USCLN(tu, mau);tu / usc mau / usctu /= usc; mau /= usc;if (mau < 0) mau = -mau, tu = -tu;if (tu == 0) mau = 1;}void PhanSo::Set(long t, long m) {(g, g){if (m) {tu = t;mau m;mau = m;UocLuoc();}4/21/2007 Lập N gôn ngữ C # T rần V ăn T èo tvteo@agu.edu.vn 01/06/2006 N g ôn n g ữ C # N ạp ch n g tác tử (operator overloading) n n L àm cho class tự tạo (u serser-d efin ed class) có th ể th ự c đư ợ c tất c củ a k iểu d ữ liệu bẩm sinh (built(built-in type) X ây dự ng hàm : Fraction theSum = firstFraction.Add(secondFraction) n T ự nhiên nh ất q u án v i k iểu d ữ liệu b ẩm sin h : Fraction theSum = firstFraction + secondFraction 01/06/2006 N g ôn n g ữ C # S dụng từ khóa operator n C ác tác tử nh ữ n g hàm static static,, có trị trả v ề k ết q u ả m ột tác vụ vớ i thơng số tác tố V í dụ: public static Fraction operator+( Fraction lhs, Fractino rhs ) n C ú pháp: Đ ặt từ khóa operator trư c tác tử cần n ạp chồng V í dụ: operator+ , operator>= , operator+= Fraction theSum = firstFraction + secondFraction Fraction theSum = Fraction.operator+(firstFraction, secondFraction) lhs  firstFraction 01/06/2006 rhs  secondFraction N g ôn n g ữ C # T ác tử q u an hệ (R elational O perator) n n N ếu overload tác tử b ằn g (= = ) th ì n ên o v errid e lu ô n hàm virtual E quals() lớ p O bject C h o phép lớ p bạn m ang tính đa hình v tư n g thích v i ngôn ng ữ N E T k h ác k h ô n g hổ trợ n ạp ch ồng tác tử public override bool Equals( object obj) { if( ! (obj is Fraction) ) { return false; } return this == (Fraction)obj; } 01/06/2006 N g ôn n g ữ C # T ác tử log ic (L og ical operator) H tác tử && || k h ô n g th ể ov erlo ad in g trự c tiếp P h ải định nghĩa tác tử : & , | , true , false H tác tử & & || tự động tính sau : n n n • • x && y x || y  T.false(x) ? x : T.&(x,y)  T.true(x) ? x : T.|(x,y) public static Fraction operator & (F ctio n a , F ctio n b ){… … } public static Fraction operator | (F ctio n a , F ctio n b ){… … } public static Fraction operator true (F ctio n a , F ctio n b ){… … } public static Fraction operator false (F ctio n a , F ctio n b ){… … } public static Fraction operator ! (F ctio n a ){… … } K h ô n g cầ n : public static Fraction operator && (Fraction a, Fraction b) public static Fraction operator a, Fraction b) 01/06/2006 N g ôn||n g(Fraction ữ C# C hu y ển đ ổ i tác tử int myInt = 5; long myLong = 7; myLong = myInt; //implicit myInt = myLong; ????  myInt = (int)myLong; //explicit Đ ịn h n g h ĩa : public static Fraction operator+( Fraction lhs, Fraction rhs ) Khai báo: Fraction a,b; int Sum; T h ự c h iệ n : b = a + 3; Sum = a + b; public static implicit operator Fraction (int th e In t) {… } public static explicit operator int (Fraction frc) {… }  01/06/2006 b = a + 3; Sum = (int)(a + b); N g ôn n g ữ C # Q&A 01/06/2006 N g ôn n g ữ C # © 2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 8 - Operator Overloading Outline 8.1 Introduction 8.2 Fundamentals of Operator Overloading 8.3 Restrictions on Operator Overloading 8.4 Operator Functions as Class Members vs. as friend Functions 8.5 Overloading Stream-Insertion and Stream-Extraction Operators 8.6 Overloading Unary Operators 8.7 Overloading Binary Operators 8.8 Case Study: Array Class 8.9 Converting between Types 8.10 Case Study: A String Class 8.11 Overloading ++ and -- 8.12 Case Study: A Date Class 8.13 Standard Library Classes string and vector © 2003 Prentice Hall, Inc. All rights reserved. 2 8.1 Introduction •Sử dụng các toán tử với các đối tượng (operator overloading) – đối với một số lớp, sử dụng toán tử trong sáng hơn sử dụng các lời gọi hàm object2 = object1.add(object2); object2 = object2 + object1; – toán tử cảm ngữ cảnh (sensitive to context) Ví dụ • << – chèn vào dòng (Stream insertion), phép dịch trái nhị phân (bitwise left-shift) • + –thực hiện tính cộng cho nhiều kiểu dữ liệu (integers, floats, etc.) © 2003 Prentice Hall, Inc. All rights reserved. 3 8.2 Fundamentals of Operator Overloading •Các kiểu dữ liệu –Có sẵn (Built in) (int, char) hoặc kiểu người dùng (user- defined) –Có thể sử dụng các toán tử có sẵn cho các kiểu dữ liệu người dùng • Không thể tạo toán tử mới • Overloading operators –Tạo một hàm của lớp – Đặt tên hàm là operator tiếp theo là ký hiệu • Operator+ dành cho phép cộng + © 2003 Prentice Hall, Inc. All rights reserved. 4 8.2 Fundamentals of Operator Overloading •Sử dụng toán tử với một đối tượng –Nó phải được overloaded cho lớp đó • ngoại trừ: • phép gán, = – phép gán từng thành viên của đối tượng này cho đối tượng kia (Memberwise assignment between objects) • toán tử địa chỉ, & –trả về địa chỉ của đối tượng •cả hai đều có thể được overloaded • Overloading cho ký hiệu ngắn gọn object2 = object1.add(object2); object2 = object2 + object1; © 2003 Prentice Hall, Inc. All rights reserved. 5 8.3 Restrictions on Operator Overloading • Không thể thay đổi: –Hoạt động của các toán tử đối với các kiểu dữ liệu có sẵn •ví dụ., không thể thay đổi phép cộng số nguyên –Thứ tự ưu tiên của các toán tử – Quan hệ kết hợp - Associativity (left-to-right hoặc right-to- left) –Số lượng toán hạng (operand) • & là toán tử đơn, chỉ dành cho một toán hạng • Không thể tạo các toán tử mới • Các toán tử phải được overloaded một cách tường minh –Overload+ không có nghĩacả += cũng được overload © 2003 Prentice Hall, Inc. All rights reserved. 6 8.3 Restrictions on Operator Overloading Operators that cannot be overloaded . .* :: ?: sizeof Operators that can be overloaded + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- ->* , -> [] () new delete new[] delete[] © 2003 Prentice Hall, Inc. All rights reserved. 7 8.4 Operator Functions As Class Members Vs. As Friend Functions • aa@bb Î aa.operator@(bb) hoặc operator@(aa,bb) • @aa Î aa.operator@( ) hoặc operator@(aa) • aa@ Î aa.operator@(int) hoặc operator@(aa,int) • Operator functions – Member functions •Sử dụng từ khóa this để ngầm lấy tham số – là toán hạng bên trái đối với các toán tử hai ngôi (ví dụ +) – là toán hạng duy nhất đối với các toán tử một ngôi • Toán tử và toán hạng bên trái nhất phải thuộc cùng lớp – Non member functions •Cần tham số cho cả hai toán hạng •Có thể lấy các đối tượng không thuộc lớp của toán tử •Phải là friend để truy nhập các dữ liệu private hoặc protected © 2003 Prentice Hall, Inc. All rights reserved. 8 8.4 Operator Functions As Class Members Vs. As Friend Functions • Các phép toán có tính giao hoán – phép + cần có tính giao hoán •cả “a + b” và “b + a” đều phải chạy được –giả sử ta có hai lớp khác © 2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 8 - Operator Overloading Outline 8.1 Introduction 8.2 Fundamentals of Operator Overloading 8.3 Restrictions on Operator Overloading 8.4 Operator Functions as Class Members vs. as friend Functions 8.5 Overloading Stream-Insertion and Stream-Extraction Operators 8.6 Overloading Unary Operators 8.7 Overloading Binary Operators 8.8 Case Study: Array Class 8.9 Converting between Types 8.10 Case Study: A String Class 8.11 Overloading ++ and -- 8.12 Case Study: A Date Class 8.13 Standard Library Classes string and vector © 2003 Prentice Hall, Inc. All rights reserved. 2 8.1 Introduction •Sử dụng các toán tử với các đối tượng (operator overloading) – đối với một số lớp, sử dụng toán tử trong sáng hơn sử dụng các lời gọi hàm object2 = object1.add(object2); object2 = object2 + object1; – toán tử cảm ngữ cảnh (sensitive to context) Ví dụ • << – chèn vào dòng (Stream insertion), phép dịch trái nhị phân (bitwise left-shift) • + –thực hiện tính cộng cho nhiều kiểu dữ liệu (integers, floats, etc.) © 2003 Prentice Hall, Inc. All rights reserved. 3 8.2 Fundamentals of Operator Overloading •Các kiểu dữ liệu –Có sẵn (Built in) (int, char) hoặc kiểu người dùng (user- defined) –Có thể sử dụng các toán tử có sẵn cho các kiểu dữ liệu người dùng • Không thể tạo toán tử mới • Overloading operators –Tạo một hàm của lớp – Đặt tên hàm là operator tiếp theo là ký hiệu • Operator+ dành cho phép cộng + © 2003 Prentice Hall, Inc. All rights reserved. 4 8.2 Fundamentals of Operator Overloading •Sử dụng toán tử với một đối tượng –Nó phải được overloaded cho lớp đó • ngoại trừ: • phép gán, = – phép gán từng thành viên của đối tượng này cho đối tượng kia (Memberwise assignment between objects) • toán tử địa chỉ, & –trả về địa chỉ của đối tượng •cả hai đều có thể được overloaded • Overloading cho ký hiệu ngắn gọn object2 = object1.add(object2); object2 = object2 + object1; © 2003 Prentice Hall, Inc. All rights reserved. 5 8.3 Restrictions on Operator Overloading • Không thể thay đổi: –Hoạt động của các toán tử đối với các kiểu dữ liệu có sẵn •ví dụ., không thể thay đổi phép cộng số nguyên –Thứ tự ưu tiên của các toán tử – Quan hệ kết hợp - Associativity (left-to-right hoặc right-to- left) –Số lượng toán hạng (operand) • & là toán tử đơn, chỉ dành cho một toán hạng • Không thể tạo các toán tử mới • Các toán tử phải được overloaded một cách tường minh –Overload+ không có nghĩacả += cũng được overload © 2003 Prentice Hall, Inc. All rights reserved. 6 8.3 Restrictions on Operator Overloading Operators that cannot be overloaded . .* :: ?: sizeof Operators that can be overloaded + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- ->* , -> [] () new delete new[] delete[] © 2003 Prentice Hall, Inc. All rights reserved. 7 8.4 Operator Functions As Class Members Vs. As Friend Functions • aa@bb Î aa.operator@(bb) hoặc operator@(aa,bb) • @aa Î aa.operator@( ) hoặc operator@(aa) • aa@ Î aa.operator@(int) hoặc operator@(aa,int) • Operator functions – Member functions •Sử dụng từ khóa this để ngầm lấy tham số – là toán hạng bên trái đối với các toán tử hai ngôi (ví dụ +) – là toán hạng duy nhất đối với các toán © 2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 8 - Operator Overloading Outline 8.1 Introduction 8.2 Fundamentals of Operator Overloading 8.3 Restrictions on Operator Overloading 8.4 Operator Functions as Class Members vs. as friend Functions 8.5 Overloading Stream-Insertion and Stream-Extraction Operators 8.6 Overloading Unary Operators 8.7 Overloading Binary Operators 8.8 Case Study: Array Class 8.9 Converting between Types 8.10 Case Study: A String Class 8.11 Overloading ++ and -- 8.12 Case Study: A Date Class 8.13 Standard Library Classes string and vector © 2003 Prentice Hall, Inc. All rights reserved. 2 8.1 Introduction •Sử dụng các toán tử với các đối tượng (operator overloading) – đối với một số lớp, sử dụng toán tử trong sáng hơn sử dụng các lời gọi hàm object2 = object1.add(object2); object2 = object2 + object1; – toán tử cảm ngữ cảnh (sensitive to context) Ví dụ • << – chèn vào dòng (Stream insertion), phép dịch trái nhị phân (bitwise left-shift) • + –thực hiện tính cộng cho nhiều kiểu dữ liệu (integers, floats, etc.) © 2003 Prentice Hall, Inc. All rights reserved. 3 8.2 Fundamentals of Operator Overloading •Các kiểu dữ liệu –Có sẵn (Built in) (int, char) hoặc kiểu người dùng (user- defined) –Có thể sử dụng các toán tử có sẵn cho các kiểu dữ liệu người dùng • Không thể tạo toán tử mới • Overloading operators –Tạo một hàm của lớp – Đặt tên hàm là operator tiếp theo là ký hiệu • Operator+ dành cho phép cộng + © 2003 Prentice Hall, Inc. All rights reserved. 4 8.2 Fundamentals of Operator Overloading •Sử dụng toán tử với một đối tượng –Nó phải được overloaded cho lớp đó • ngoại trừ: • phép gán, = – phép gán từng thành viên của đối tượng này cho đối tượng kia (Memberwise assignment between objects) • toán tử địa chỉ, & –trả về địa chỉ của đối tượng •cả hai đều có thể được overloaded • Overloading cho ký hiệu ngắn gọn object2 = object1.add(object2); object2 = object2 + object1; © 2003 Prentice Hall, Inc. All rights reserved. 5 8.3 Restrictions on Operator Overloading • Không thể thay đổi: –Hoạt động của các toán tử đối với các kiểu dữ liệu có sẵn •ví dụ., không thể thay đổi phép cộng số nguyên –Thứ tự ưu tiên của các toán tử – Quan hệ kết hợp - Associativity (left-to-right hoặc right-to- left) –Số lượng toán hạng (operand) • & là toán tử đơn, chỉ dành cho một toán hạng • Không thể tạo các toán tử mới • Các toán tử phải được overloaded một cách tường minh –Overload+ không có nghĩacả += cũng được overload © 2003 Prentice Hall, Inc. All rights reserved. 6 8.3 Restrictions on Operator Overloading Operators that cannot be overloaded . .* :: ?: sizeof Operators that can be overloaded + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- ->* , -> [] () new delete new[] delete[] © 2003 Prentice Hall, Inc. All rights reserved. 7 8.4 Operator Functions As Class Members Vs. As Friend Functions • aa@bb Î aa.operator@(bb) hoặc operator@(aa,bb) • @aa Î aa.operator@( ) hoặc operator@(aa) • aa@ Î aa.operator@(int) hoặc operator@(aa,int) • Operator functions – Member functions •Sử dụng từ khóa this để ngầm lấy tham số – là toán hạng bên trái đối với các toán tử hai ngôi (ví dụ +) – là toán hạng duy nhất đối với các toán tử một ngôi • Toán tử và toán hạng bên trái nhất phải thuộc cùng lớp – Non member functions •Cần tham số cho cả hai toán hạng •Có thể lấy các đối tượng không thuộc lớp của toán tử •Phải là friend để truy nhập các dữ liệu private hoặc protected © 2003 Prentice Hall, Inc. All rights reserved. 8 8.4 Operator Functions As Class Members Vs. As Friend Functions • Các phép toán có tính giao hoán – phép + cần có tính giao hoán •cả “a + b” và “b + a” đều phải chạy được –giả sử ta có hai lớp khác  2003 Prentice Hall, Inc. All rights reserved. 1 Chapter 8 - Operator Overloading             !"!"#$  % &' ( )'  !'*+' , -.' / !'*+String  ++  !'*+Date  !0'stringvector  2003 Prentice Hall, Inc. All rights reserved. 2  • Use operators with objects (operator overloading) – Clearer than function calls for certain classes – Operator sensitive to context • Examples – << • Stream insertion, bitwise left-shift – + • Performs arithmetic on multiple types (integers, floats, etc.) • Will discuss when to use operator overloading  2003 Prentice Hall, Inc. All rights reserved. 3   • Types – Built in (int, char) or user-defined – Can use existing operators with user- defined types • Cannot create new operators • Overloading operators – Create a function for the class – Name function operator followed by symbol • Operator+ for the addition operator +  2003 Prentice Hall, Inc. All rights reserved. 4   • Using operators on a class object – It must be overloaded for that class • Exceptions: • Assignment operator, = – Memberwise assignment between objects • Address operator, & – Returns address of object • Both can be overloaded • Overloading provides concise notation – object2 = object1.add(object2); – object2 = object2 + object1;  2003 Prentice Hall, Inc. All rights reserved. 5   • Cannot change – How operators act on built-in data types • I.e., cannot change integer addition – Precedence of operator (order of evaluation) • Use parentheses to force order-of-operations – Associativity (left-to-right or right-to- left) – Number of operands • & is unitary, only acts on one operand • Cannot create new operators • Operators must be overloaded explicitly – Overloading + does not overload +=  2003 Prentice Hall, Inc. All rights reserved. 6   Operators that cannot be overloaded . .* :: ?: sizeof Operators that can be overloaded + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ ->* , -> [] () new delete new[] delete[]  2003 Prentice Hall, Inc. All rights reserved. 7 + 1+ • Operator functions – Member functions • Use this keyword to implicitly get argument • Gets left operand for binary operators (like +) • Leftmost object must be of same class as operator – Non member functions • Need parameters for both operands • Can have object of different class than operator • Must be a friend to access private or protected data – Called when • Left operand of binary operator of same class • Single operand of unitary operator of same class  2003 Prentice Hall, Inc. All rights reserved. 8 + 1+ • Overloaded << operator – Left operand of type ostream & • Such as cout object in cout << classObject – Similarly, overloaded >> needs istream & – Thus, both must be non-member functions  2003 Prentice Hall, Inc. All rights reserved. 9 + 1+ • Commutative operators – May want + to be commutative • So both “a + b” and “b + a” work – Suppose we have two different classes – Overloaded operator can only be member function when its ... pháp: Đ ặt từ khóa operator trư c tác tử cần n ạp chồng V í dụ: operator+ , operator> = , operator+ = Fraction theSum = firstFraction + secondFraction Fraction theSum = Fraction .operator+ (firstFraction,... T.|(x,y) public static Fraction operator & (F ctio n a , F ctio n b ){… … } public static Fraction operator | (F ctio n a , F ctio n b ){… … } public static Fraction operator true (F ctio n a , F... } public static Fraction operator false (F ctio n a , F ctio n b ){… … } public static Fraction operator ! (F ctio n a ){… … } K h ô n g cầ n : public static Fraction operator && (Fraction a,

Ngày đăng: 05/11/2017, 03:39