Lập trình hướng đối tượng với C++ - Chương 4: Định nghĩa toán tử trên lớp
Ngôn ngữ C++
Định nghĩa toán tử trên lớp
-160-
-170-
-109-
1. Giới thiệu chung 109
2. Ví dụ trên lớp số phức 110
2.1 Hàm toán tử là hàm thành phần 110
2.2 Hàm toán tử là hàm bạn 112
3. Khả năng và giới hạn của định nghĩa chồng toán tử 122
Phần lớn toán tử trong C++ đều có thể định nghĩa chồng 122
Trường hợp các toán tử ++ và -- 123
Lựa chọn giữa hàm thành phần và hàm bạn 124
4. Chiến lược sử dụng hàm toán tử 124
Các phép toán một ngôi 124
Các phép toán hai ngôi 124
Các phép gán 124
Toán tử truy nhập thành phần “->” 125
Toán tử truy nhập thành phần theo chỉ số 125
Toán tử gọi hàm 125
5. Một số ví dụ tiêu biểu 125
5.1 Định nghĩa chồng phép gán “ =” 125
5.2 Định nghĩa chồng phép “[]" 130
5.3 Định nghĩa chồng << và >> 133
5.4 Định nghĩa chồng các toán tử new và delete 135
5.5 Phép nhân ma trận véc tơ 137
6. Chuyển đổi kiểu 142
6.1 Hàm toán tử chuyển kiểu ép buộc 143
6.1.1 Hàm toán tử chuyển kiểu trong lời gọi hàm 145
6.1.2 Hàm toán tử chuyển kiểu trong biểu thức 147
6.2 Hàm toán tử chuyển đổi kiểu cơ sở sang kiểu lớp 148
6.2.1 Hàm thiết lập trong các chuyển đổi kiểu liên tiếp 150
6.2.2 Lựa chọn giữa hàm thiết lập và phép toán gán 150
6.2.3 Sử dụng hàm thiết lập để mở rộng ý nghĩa một phép toán 152
6.3 Chuyển đổi kiểu từ lớp này sang một lớp khác 154
6.3.1 Hàm toán tử chuyển kiểu bắt buộc 154
6.3.2 Hàm thiết lập dùng làm hàm toán tử 156
7. Tóm tắt 157
7.1 Ghi nhớ 157
7.2 Các lỗi thường gặp 158
7.3 Một số thói quen lập trình tốt 158
8. Bài tập 158
"Ham thiet lap \n"; real = r; image = i; } complex(complex &b) { cout<<"Ham thiet lap sao chep lai "<<&b<<" Sang "<<this<<endl; real = b.real; image = b.image; } }; void fct(complex p) { cout<<"Goi fct \n"; } void main() { clrscr(); complex a(3,4); a = complex(12); a = 12; fct(4); getch(); } Ham thiet lap Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh Goi fct Hàm thiết lập trong các chuyển đổi kiểu liên tiếp Trong lớp số phức complex hàm thiết lập với một tham số cho phép thực hiện chuyển đổi float -->complex đồng thời cả chuyển đổi ngầm định int --> float. tức là nó có thể cho phép một chuỗi các chuyển đổi: int --> float -->complex Chẳng hạn khi gặp phép gán kiểu như: a = 2; Cần chú ý khả năng chuyển đổi này phải dựa trên các quy tắc chuyển đổi thông thường như đã nói ở trên. Lựa chọn giữa hàm thiết lập và phép toán gán Với chỉ thị gán: a=12; trong chương trình complex9.cpp không có định nghĩa toán tử gán một số nguyên cho một đối tượng complex. Giả sử có một toán tử gán như vậy thì có thể sẽ xảy ra xung đột giữa: chuyển đổi float-->complex bởi hàm thiết lập và phép gán complex-->complex. sử dụng trực tiếp toán tử gán float-->complex. Để giải quyết vấn đề này ta tuân theo quy tắc : “Các chuyển đổi do người sử dụng định nghĩa chỉ được thực hiện khi cần thiết”, nghĩa là với chỉ thị gán: a = 12; nếu như trong lớp complex có định nghĩa toán tử gán, nó sẽ được ưu tiên thực hiện. Chương trình sau đây minh hoạ nhận xét này: Ví dụ 4.15 /*complex10.cpp*/ #include #include class complex { float real, image; public: complex(float r) { cout<<"Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh\n"; real = r; image = 0; } complex(float r, float i ) { cout<<"Ham thiet lap \n"; real = r; image = i; } complex & operator=(complex &p) { real = p.real;image = p.image; coutcomplex tu "<<&p<<" sang "<<this<<endl; return *this; } complex & operator=(float n) { real = n;image = 0; coutcomplex "<<endl; return *this; } }; void main() { clrscr(); complex a(3,4); a = 12; getch(); } Ham thiet lap gan float -->complex Sử dụng hàm thiết lập để mở rộng ý nghĩa một phép toán Ta xét lớp complex và hàm thiết lập một tham số của lớp được bổ sung thêm một hàm toán tử dưới dạng hàm bạn (trường hợp này không nên sử dụng hàm toán tử thành phần). Với các điều kiện này, khi a là một đối tượng kiểu complex, biểu thức kiểu như: a + 3 sẽ có ý nghĩa. Thực vậy trong trường hợp này chương trình dịch sẽ thực hiện các thao tác sau: chuyển đổi từ số thực 3 sang số phức complex. cộng giữa đối tượng nhận được với a bằng cách gọi hàm toán tử operator+. Kết quả sẽ là một đối tượng kiểu complex. Nói cách khác, biểu thức a + 3 tương đương với operator+(a, point(3)). Tương tự, biểu thức 5 + a sẽ tương đương với: operator+(point(5),a). Tuy nhiên trường hợp sau sẽ không còn đúng khi operator+ là hàm toán tử thành phần. Sau đây là một chương trình minh hoạ các khả năng mà chúng ta vừa đề cập. Ví dụ 4.16 /*complex11.cpp*/ #include #include #include class complex { float real, image; public: complex(float r) { cout<<"Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh\n"; real = r; image = 0; } complex(float r, float i ) { cout<<"Ham thiet lap 2 tham so\n"; real = r; image = i; } void display() { cout=0?"+j*":"-j*")<<fabs(image)<<endl; } friend complex operator+(complex , complex); }; complex operator+(complex a, complex b) { complex c(0,0); c.real = a.real + b.real; c.image = a.image + b.image; return c; } void main() { clrscr(); complex a(3,4),b(9,4); a = b + 5;a.display(); a = 2 + b;a.display(); getch(); } Ham thiet lap 2 tham so Ham thiet lap 2 tham so Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh Ham thiet lap 2 tham so 14+j*4 Ham thiet lap dong vai tro cua ham toan tu chuyen kieu ngam dinh Ham thiet lap 2 tham so 11+j*4 Nhận xét Hàm thiết lập làm nhiệm vụ của hàm toán tử chuyển đổi kiểu cơ sở sang kiểu lớp không nhất thiết chỉ có một tham số hình thức. Trong trường hợp hàm thiết lập có nhiều tham số hơn, các tham số tính từ tham số thứ hai phải có giá trị ngầm định. Chuyển đổi kiểu từ lớp này sang một lớp khác Khả năng chuyển đổi qua lại giữa kiểu cơ sở và một kiểu lớp có thể được mở rộng cho hai kiểu lớp khác nhau: Trong lớp A, ta có thể định nghĩa một hàm toán tử để thực hiện chuyển đổi từ kiểu A sang kiểu B (cast operator). Hàm thiết lập của lớp A chỉ với một tham số kiểu B sẽ thực hiện chuyển đổi kiểu từ B sang A. Hàm toán tử chuyển kiểu bắt buộc Ví dụ sau đây minh hoạ khả năng dùng hàm toán tử complex của lớp point cho phép thực hiện chuyển đổi một đối tượng kiểu point thành một đối tượng kiểu complex. Ví dụ 4.17 /*pointcomplex1.cpp*/ #include #include #include class complex;//khai báo trước lớp complex class point { int x, y; public: point(int ox = 0, int oy =0) {x = ox; y = oy;} operator complex();//chuyển đổi point-->complex }; class complex { float real, image; public: complex(float r=0, float i=0 ) { real = r; image = i; } friend point::operator complex(); void display() { cout=0?"+j*":"-j*")<<fabs(image)<<endl; } }; point::operator complex() { complex r(x,y); cout<<"Chuyen doi "<<x<<" "<<y <<" thanh "<<r.real<<" + "<< r.image<<endl; return r; } void main() { clrscr(); point a(2,5); complex c; c = (complex) a; c.display(); point b(9,12); c = b; c.display(); getch(); } Chuyen doi 2 5 thanh 2 + 5 2+j*5 Chuyen doi 9 12 thanh 9 + 12 9+j*12 Hàm thiết lập dùng làm hàm toán tử Chương trình sau đây minh hoạ khả năng dùng hàm thiết lập complex(point) biểu để thực hiện chuyển đổi một đối tượng kiểu point thành một đối tượng kiểu complex. Ví dụ 4.18 /*pointcomplex2.cpp*/ #include #include #include class point;//khai báo trước lớp complex class complex { float real, image; public: complex(float r=0, float i=0 ) { real = r; image = i; } complex(point); void display() { cout=0?"+j*":"-j*")<<fabs(image)<<endl; } }; class point { int x, y; public: point(int ox = 0, int oy =0) {x = ox; y = oy;} friend complex::complex(point); }; complex::complex(point p) { real= p.x; image = p.y; } void main() { clrscr(); point a(3,5); complex c = a; c.display(); getch(); } 3+j*5 Tóm tắt Ghi nhớ Toán tử được định nghĩa chồng bằng cách định nghĩa một hàm toán tử. Tên hàm toán tử bao gồm từ khoá operator theo sau là ký hiệu của toán tử được định nghĩa chồng. Hầu hết các toán tử của C++ đều có thể định nghĩa chồng. Không thể tạo ra các ký hiệu phép toán mới. Phải đảm bảo các đặc tính nguyên thuỷ của toán tử được định nghĩa chồng, chẳng hạn: độ ưu tiên, trật tự kết hợp, số ngôi . Không sử dụng tham số có giá trị ngầm định để định nghĩa chồng toán tử. Các toán tử (), [], ->, = yêu cầu hàm toán tử phải là hàm thành phần của lớp. Hàm toán tử có thể là hàm thành phần hoặc hàm bạn của lớp. Khi hàm toán tử là hàm thành phần, toán hạng bên trái luôn là đối tượng thuộc lớp. Nếu toán hạng bên trái là đối tượng của lớp khác thì hàm toán tử tương ứng phải là hàm bạn. Chương trình dịch không tự biết cách chuyển kiểu giữa kiểu dữ liệu chuẩn và kiểu dữ liệu tự định nghĩa. Vì vậy người lập trình cần phải mô tả tường minh các chuyển đổi này dưới dạng hàm thiết lập chuyển kiểu hay hàm toán tử chuyển kiểu. Một hàm toán tử chuyển kiểu thực hiện chuyển đổi từ một đối tượng thuộc lớp sang đối tượng thuộc lớp khác hoặc một đối tượng có kiểu được định nghĩa trước. Hàm thiết lập chuyển kiểu có một tham số và thực hiện chuyển đổi từ một giá trị sang đối tượng kiểu lớp. Toán tử gán là toán tử hay được định nghĩa chồng nhất, đặc biệt khi lớp có các thành phần dữ liệu động. Để định nghĩa chồng toán tử tăng, giảm một ngôi, phải phân biệt hai hàm toán tử tương ứng cho dạng tiền tố và dạng hậu tố. Các lỗi thường gặp Tạo một toán tử mới. Thay đổi định nghĩa của các toán tử trên các kiểu được định nghĩa trước. Cho rằng việc định nghĩa chồng một toán tử sẽ tự đông kéo theo định nghĩa chồng của các toán tử liên quan. Quên định nghĩa chồng toán tử gán và hàm thiết lập sao chép cho các lớp có các thành phần dữ liệu động. Một số thói quen lập trình tốt Sử dụng toán tử định nghĩa chồng khi điều đó làm cho chương trình trong sáng hơn. Tránh lạm dụng định nghĩa chồng toán tử vì điều đó dẫn đến khó kiểm soát chương trình. Chú ý đến các tính chất nguyên thuỷ của toán tử được định nghĩa chồng. Hàm thiết lập, toán tử gán, hàm thiết lập sao chép của một lớp thường đi cùng nhau. Bài tập Bài tập 4.1. Bổ sung thêm một số toán tử trên lớp số phức complex. Định nghĩa hai phép toán vào ra trên lớp vector. Bài tập 4.2. Một ma trận được hiểu là một vector mà mỗi thành phần của nó lại là một vector. Theo tinh thần đó hãy định nghĩa lớp matrix dựa trên vector. Tìm cách để cho chương trình dịch hiểu được phép truy nhập m[i][j] trong đó m là một đối tượng thuộc lớp matrix. Bài tập 4.3. Định nghĩa các phép nhân, cộng, trừ trên các ma trận vuông. Bài tập 4.4. Dựa trên định nghĩa của lớp complex , lớp vector và lớp matrix để xây dựng chương trình mô phỏng các thao tác trên ma trận và vector phức. Bài tập 4.5. Thay thế hàm thành phần tick() trong lớp date_time bài tập 3.10 bởi hàm toán tử tương ứng với phép toán ++. Bài tập 4.6. Tạo lớp phân số PS với các khả năng sau: Tạo một hàm thiết lập với mẫu số dương, ở dạng tối giản hoặc rút gọn về dạng tối giản. Định nghĩa chồng các toán tử cộng, trừ, nhân, chia cho lớp này. Định nghĩa chồng các toán tử quan hệ trên lớp số phức.
File đính kèm:
- Lập trình hướng đối tượng với C++ - Chương 4 Định nghĩa toán tử trên lớp.doc