KHƠNG LÀ CÁC THÀNH VIÊN
Các hàm tốn tử có thể là các hàm thành viên hoặc hàm khơng thành viên; hàm không thành viên thường là các hàm friend. Các hàm thành viên sử dụng ngầm con trỏ this để chứa một trong các tham số đối tượng lớp của chúng. Tham số lớp đó phải được liệt kê một cách tường minh trong lời gọi hàm không thành viên.
Khi đa năng hóa (), [], -> hoặc =, hàm đa năng hóa tốn tử phải được khai báo như một thành viên lớp.
Đối với các toán tử khác, các hàm đa năng hóa tốn tử có thể là các hàm không thành viên (thường là các
hàm friend).
Liệu có phải một hàm tốn tử được cài đặt như một hàm thành viên hoặc như hàm khơng thành viên, tốn tử vẫn cịn được sử dụng cùng cách trong biểu thức. Như vậy cách là cách cài đặt nào tốt nhất?
Khi một hàm toán tử được cài đặt như một hàm thành viên, toán hạng cực trái phải là một đối tượng lớp của toán tử. Nếu toán hạng bên trái phải là một đối tượng của lớp khác hoặc một kiểu có sẵn thì hàm tốn tử này phải được cài đặt như hàm khơng thành viên. Một hàm tốn tử cài đặt như hàm không thành viêân cần là một friend nếu hàm phải truy cập đến các thành viên private hoặc protected.
Các hàm thành viên chỉ được gọi khi toán hạng trái của một tốn tử hai ngơi là một đối tượng cụ thể của lớp đó, hoặc khi tốn hạng đơn của một tốn tử một ngơi là một đối tượng của lớp đó.
78
Ví dụ 4.1: Chúng ta xây dựng lớp số phức với tên lớp là Complex và đa năng hóa tốn tử + trên lớp này.
1: #include <iostream.h> 2:
3: class Complex 4: {
5: private:
6: double Real, Imaginary; 7: public:
8: Complex(double R=0.0,double I=0.0);// Constructor mặc định 9: void Print(); // Hiển thị số phức
10: Complex operator+(Complex Z); // Phép cộng giữa hai số phức 11: Complex operator+(double R); //cộng một số phức với một số thực 12: }; 13: 14: Complex::Complex(double R,double I) 15: { 16: Real = R; 17: Imaginary = I; 18: } 19: 20: void Complex::Print() 21: { 22: cout<<'('<<Real<<','<<Imaginary<<')'; 23: } 24:
25: Complex Complex::operator + (Complex Z) 26: {
27: Complex Tmp;
28: Tmp.Real = Real + Z.Real;
29: Tmp.Imaginary = Imaginary + Z.Imaginary; 30: return Tmp;
31: } 32:
33: Complex Complex::operator + (double R) 34: { 35: Complex Tmp; 36: Tmp.Real = Real + R; 37: Tmp.Imaginary = Imaginary; 38: return Tmp; 39: } 40: 41: int main() 42: { 43: Complex X,Y(4.3,8.2),Z(3.3,1.1); 44: cout<<"X: "; 45: X.Print(); 46: cout<<endl<<"Y: "; 47: Y.Print(); 48: cout<<endl<<"Z: "; 49: Z.Print(); 50: X = Y + Z; 51: cout<<endl<<endl<<"X = Y + Z:"<<endl; 52: X.Print(); 53: cout<<" = "; 54: Y.Print(); 55: cout<<" + "; 56: Z.Print();
Giáo trình mơn Lập trình hướng đối tượng Trang 79 57: X = Y + 3.5; 58: cout<<endl<<endl<<"X = Y + 3.5:"<<endl; 59: X.Print(); 60: cout<<" = "; 61: Y.Print(); 62: cout<<" + 3.5"; 63: return 0; 64: }
Hàm thành viên toán tử operator + () (từ dòng 25 đến 31 và từ dòng 33 đến 39) trả về một đối tượng có kiểu Complex là tổng của hai số phức hoặc tổng của một số phức với một số thực. Chú ý rằng đối tượng tam thời Tmp được dùng bên trong hàm operator + () để giữ kết quả, và đó là đối tượng được trả về.
Chúng ta chạy ví dụ 4.1, kết quả ở hình 4.3
Hình 4.3: Kết quả của ví dụ 4.1
Do đa năng hóa tốn tử + trên lớp Complex ở ví dụ 4.1, chúng ta có thể viết: X = Y + Z;
Câu lệnh này được trình biên dịch hiểu: X = Y.operator + (Z);
Như vậy, trong biểu thức Y + Z đối tượng bên trái toán tử + (là đối tượng Y) là đối tượng mà qua đó,
hàm thành viên tốn tử operator + () được gọi. Do đó hàm thành viên tốn tử + chỉ nhận một tham số là đối tượng bên phải toán tử và đối tượng bên trái toán tử là đối tượng tạo lời gọi cho hàm toán tử và được truyền bởi con trỏ this.
Hàm operator + () trả về một đối tượng Complex. Do vậy chúng ta có thể viết: (Y + Z).Print();
để in trên màn hình số phức của đối tượng được trả về. Đối tượng do Y + Z sinh ra như vậy là một đối
tượng tạm thời. Nó sẽ khơng tồn tại khi hàm thành Print() kết thúc.
Hơn nữa khi trả về một đối tượng, toán tử + cho phép một chuỗi phép cộng. Nên chúng ta cũng có thể viết:
X = X + Y + Z;
Tuy nhiên chúng ta không thể nào viết được câu lệnh sau: X = 3.5 + Y; // Lỗi !!!
Chính vì lý do này chúng ta chọn một hàm khơng thành viên để đa năng hóa một toán tử để cho phép toán tử được giao hốn. Chú ý rằng hàm khơng thành viên khơng cần thiết phải là hàm friend nếu các hàm set và get thích hợp tồn tại trong phần giao diện public, và đặt biệt nhất nếu các hàm set và get là các hàm
80
Để đa năng hóa tốn tử << phải có một tốn hạng trái của kiểu ostream & (như là cout trong biểu thức
cout<<X), vì thế nó phải là hàm không thành viên. Tương tự, đa năng hóa tốn tử >> phải có một tốn hạng trái của kiểu istream & (như là cin trong biểu thức cin>>X), vì thế vì thế nó cũng phải là hàm khơng thành viên.
Ngoại trừ đa năng hóa tốn tử >> và << liên quan đến dòng nhập/xuất dữ liệu chúng ta có hình 4.4 về cách đa năng hóa tốn tử như sau:
Biểu thức Hàm thành viên Hàm không thành viên
a#b a.operator#(b) operator#(a,b) #a a.operator() operator#(a) a=b a.operator=(b)
a[b] a.operator[](b) a(b) a.operator()(b) a-> a.operator->()
a++ a.operator++(0) operator++(a,0) a-- a.operator--(0) operator--(a,0)
Hình 4.4: Việc cài đặt các hàm toán tử