^Back To Top
Trong ngôn ngữ lập trình C++ để thực hiện các phép toán +, -, *, / của các cấu trức dữ liệu toán học như int, double, float, … được thực hiện một cách bình thường. Đối với cấu trúc phân số hoặc số phức thì ta phải viết hàm để thực hiện các phép toán đó.
Ví dụ hàm cộng và trừ 2 phân số:
struct PS {
int ts, ms;};
PS cong(PS x, PS y){
PS temp;
temp.ts = x.ts*y.ms + x.ms*y.ts;
temp.ms = x.ms*y.ms;
return temp;}
PS tru(PS x, PS y){
PS temp;
temp.ts = x.ts*y.ms - x.ms*y.ts;
temp.ms = x.ms*y.ms;
return temp;}
Giả sử cần tính giá trị của các biểu thức:
s1 = a + b - c;
Với a, b, c là các phân số thì ta phải viết:
s1 = tru(cong(a,b),c);
Rõ ràng cách gọi như vậy là không trực quan bằng cách viết trực tiếp công thức trong khi lập trình. Hơn nữa khi ta có một biểu thức phức tạp hơn, nếu viết bằng lời gọi hàm như cộng, trừ, đảo dấu quả là phức tạp. Để khắc phục điều này trong C++ định nghĩa chồng các toán tử.
PS operator +(PS x, PS y){
PS temp;
temp.ts = x.ts*y.ms + x.ms*y.ts;
temp.ms = x.ms*y.ms;
return temp;}
PS operator -(PS x, PS y){
PS temp;
temp.ts = x.ts*y.ms - x.ms*y.ts;
temp.ms = x.ms*y.ms;
return temp;}
Khi đó s1= a+b-c;
1. Hàm toán tử là hàm thành phần
Hàm toán tử thành phần có một tham số ngầm định là đối tượng gọi hàm nên chỉ có một tham số tường minh.
Ví dụ: hàm cộng 2 phân số
// hamf operator + dinh nghia phep toan + hai ngoi tren lop so phuc complex
phanso operator+(phanso b){
phanso c;
c.ts=ts*b.ms+ms*b.ts;
c.ms=ms*b.ms;
return c;
}
chỉ thị: c=a+b;
trong chương trình trên được chương trình dịch hiểu là:
c=a.opertor+(b);
Nhận xét:
1. Cách viết a+b chỉ là một quy ước của chương trình dịch cho phép người sử dụng viết gọn lại.
2. Hàm toán tử operator+ phải có thuộc tính public vì nếu không chương trình dịch không thể thực hiện được nó ở ngoài phạm vi lớp.
3. Trong lời gọi hàm a.operator+(b), a đóng vai trò của tham số ngầm định của hàm thành phần và b là tham số tường minh. Số tham số tường minh cho hàm toán tử thành phần luôn ít hơn số ngôi của phép toán là 1 vì có một tham số ngầm định là đối tượng gọi hàm toán tử.
4. Chương trình dịch sẽ không thể hiểu được biểu thức 3+a vì cách viết tương ứng 3.operator(a) không có ý nghĩa. Để giải quyết tình huống này ta dùng hàm bạn để định nghĩa hàm toán tử.
2. Hàm toán tử là hàm bạn
Trong trường hợp này sử dụng 2 tham số để thực hiện việc gọi định nghĩa hàm. Khi sử dụng ta phải khai báo hàm bạn trong lớp rồi mới định nghĩa toán tử khi ra khỏi lớp.
Ví dụ bài phân số:
friend phanso operator+(phanso P1,phanso P2);
};
phanso operator +(phanso P1, phanso P2){
phanso P;
P.ts= P1.ts*P2.ms + P1.ms * P2.ts;
P.ms = P1.ms *P2.ms;
Return P;}
Trong chương trình trên, biểu thức a+b được chương trình hiểu là lời gọi hàm thành phần a.operator+(b), trong khi đó với biểu thức 3+a, chương trình dịch sẽ thực hiện lời gọi hàm tự do operator+(3,a).
Số tham số trong hàm toán tử tự do operator+(…) đúng bằng số ngôi của phép + mà nó định nghĩa. Trong định nghĩa của hàm toán tử tự do, tham số thứ nhất có thể có kiểu bất kỳ chứ không nhất thiết phải có kiểu lớp nào đó.
Với một hàm operator+ nào đó chỉ có thể thực hiện được phép + tương ứng giữa hai toán hạng có kểiu như đã được mô tả trong tham số hình thức, nghĩa là muốn có được phép cộng “ vạn năng” áp dụng cho mọi kiểu toán hạng ta phải định nghĩa rất nhiều hàm toán tử operator+ ( định nghĩa chồng các toán tử);
Vấn đề bảo toán các tính chất tự nhiên của các phép toán không được c++ đề cập, mà nó phụ thuộc vào cách cài đặt cụ thể trong chương trình dịch c++ hoặc bản thân người sử dụng khi định nghĩa các hàm toán tử. Chẳng hạn, phép gán:
c=a+b;
Được chương trình dịch hiểu như là: c=a.operator+(b); trong khi đó phép gán:
d=a+b+c;
Ngôn ngữ c++ không đưa ra diễn giải nghĩa duy nhất. Một số chương trình biên dịch sẽ tạo ra đối tượng trung gian t:
t=a.operator+(b);
c=t.operator+(c);
3. Khả năng và giới hạn của định nghĩa chồng toán tử
Phần lớn toán tử trong C++ đều có thể định nghĩa chồng toán tử
Ký hiệu đứng sau từ khoá operator phải là một trong số các ký hiệu toán tử áp dụng cho các kiểu dữ liệu cơ sở, không thể dùng các ký hiệu mới. Một số toán tử không thể định nghĩa chồng ( chẳng hạn toán tử truy nhập thành phần cấu trúc “.”, toán tử phạm vi “::”, toán tử điều kiện “?” ”) và có một số toán tử ta phải tuân theo các ràng buộc sau:
Các toán tử được định nghĩa chồng phải bảo toàn số ngôi của chính toán tử đó theo cách hiểu thông thường. Ví dụ: có thể định nghĩa toán tử “-“ một ngôi và hai ngôi trên lớp tương ứng với phép đảo dấu ( một ngôi) và phép trừ số học ( hai ngôi) nhưng không thể định nghĩa toán tử gán một ngôi, còn c++ lại cho hai ngôi. Nếu làm vậy, chương trình dịch sẽ hiểu là tạo ra một ký hiệu phép toán mới.
Khi định nghĩa chồng toán tử, phải tuân theo nguyên tắc là một trong số các toán hạng phải là đối tượng. Nói cách khác, hàm toán tử phải:
(ii) Hoặc là một hàm tự do. Trong trường hợp này, ít nhất tham số thứ nhất hoặc tham số thứ hai phải có kiểu lớp.
Hơn nữa, mỗi hàm toán tử chỉ có thể áp dụng với kiểu toán hạng nhất định, cần chú ý rằng các tính chất vốn có, chẳng hạn tính giao hoàn của toán tử không thể áp dụng một cách tuỳ tiện cho các toán tử được định nghĩa chồng.
Ví dụ:
a+3.5
khác với 3.5+a;
Cần lưu ý rằng không nên định nghĩa những hàm toán tử khác nhau cùng làm những công việc giống nhau vì dễ xảy ra nhập nhằng. Chẳng hạn, đã có một hàm operator+ là một hàm thành phần có tham số là đối tượng complex (số phức) thì không được định nghĩa thêm một hàm operator+ là một hàm tự do có 2 tham số là đối tượng complex.