Bài giảng Lập trình hướng đối tượng - Chương 4: Quá tải hàm
• Quá tải hàm tạo
• Hàm tạo bản sao
• Hàm với các đối số mặc định
• Tính không xác định khi quá tải hàm
• Điạ chỉ của hàm quá tải
Tóm tắt nội dung Bài giảng Lập trình hướng đối tượng - Chương 4: Quá tải hàm, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
ậy, các đối số ngầm định thường đưa ra cách đơn giản để quá tải hàm. • Trong phần trước, một hàm tạo được quá tải chiû cho phép tạo ra các đối tượng được khởi đầu vẫn không được khởi đầu. Trong nhiều trường hợp, có thể tránh quá tải một hàm tạo bằng cách cho nó một hay nhiều đối số ngầm định. Ví dụ 3.4 #include class myclass { int x; public: /* Use default argument instead of overloading myclass's constructor. */ myclass(int n = 0) { x = n; } int getx() { return x; } }; int main() { myclass o1(10); // declare with initial value myclass o2; // declare without initializer Chương 4 Quá tải hàm 123 123 cout << "o1: " << o1.getx() << '\n'; cout << "o2: " << o2.getx() << '\n'; return 0; } @ Như vậy, bằng cách cho biến n giá trị mặc định zero, có thể tạo ra các đối tượng có các giá trị đầu rõ ràng và các đối tượng có giá trị mặc định là đủ. • Đối số mặc định được tìm thấy khi một tham số được dùng để chọn một tùy chọn. Ví dụ 3.5 #include #include const int ignore = 0; const int upper = 1; const int lower = 2; void print(char *s, int how = -1) ; int main() { print("Hello There\n", ignore); print("Hello There\n", upper); print("Hello There\n"); // continue in upper print("Hello there\n", lower); print("That's all\n"); // continue in lower return 0; } /* Print a string in the specified case. Use last case specified if none is given. */ void print(char *s, int how) { static int oldcase = ignore; Chương 4 Quá tải hàm 124 124 // reuse old case if none specified if(how < 0) how = oldcase; while(*s) { switch(how) { case upper : cout << (char) toupper(*s); break; case lower : cout << (char) tolower(*s); break; default : cout << *s; } s++; } oldcase = how; } • Thực sự, việc cung cấp đối số mặc định khi không được gọi sẽ làm hỏng chương trình và sẽ hướng dẫn sai cho người khác sử dụng hàm đó. Với sự quá tải hàm, một lập trình viên thành thạo sẽ biết được khi nào thì sử dụng đối số mặc định và khi nào không. Chương 4 Quá tải hàm 125 125 Bài tập III 1. Tìm lỗi sai trong nguyên mẫu hàm sau : char *f(char *p, int x = 0 , char *q) ; 2. Tìm lỗi sai trong nguyên mẫu dùng đối số mặc định sau : int f(int count, int max = count) ; 3. Trong thư viện chuẩn C++ có hàm strtol(), có nguyên mẫu sau : long strtol(const char *start, const **end, int base); Hàm này chuyển đổi chuỗi số được trỏ tới bởi start thành số nguyên dài. Hãy tạo hàm mystrtol() hoạt động giống như strtol() với ngoại lệ là base được cho một đối số mặc định là 10. Viết chương trình chứng tỏ hàm mystrtol() hoạt động tốt. 4. Hãy tạo hàm myclreol() để xoá dòng từ vị trí con trỏ hiện tại đến cuối dòng. Hàm này có một tham số chỉ rõ vị trí của ký tự cần xoá. Nếu không chỉ rõ tham số thì toàn bộ dòng sẽ tự động bị xoá. Ngược lại, chỉ xoá những vị trí nào được chỉ rõ bởi tham số. IV/ Sự quá tải và tính không xác định (ambiguity) Chương 4 Quá tải hàm 126 126 Khi quá tải hàm, có thể dẫn đến tính không xác định trong chương trình. Tính không xác định do quá tải gây ra có thể được đưa vào thông qua : + các chuyển đổi kiểu + các tham số tham chiếu + các đối số mặc định + hoặc do chính các hàm được quá tải + hoặc do cách gọi các hàm quá tải Tính không xác định phải được loại bỏ trước khi chương trình được biên dịch. • Tính không xác định gây ra bởi các quy tắc chuyển đổi kiểu tự động trong C++ Ví dụ 4.1 // This program contains an ambiguity error. #include float f(float i) { return i / 2.0; } double f(double i) { return i / 3.0; } int main() { float x = 10.09; double y = 10.09; cout << f(x); // unambiguous - use f(float) cout << f(y); // unambiguous - use f(double) Chương 4 Quá tải hàm 127 127 cout << f(10); // ambiguous, convert 10 to double or float?? return 0; } @ Lỗi biên dịch có dạng Error : Ambiguity between 'f(float)' and 'f(double)' @ Ví dụ trên minh họa tính không xác định có thể xảy ra khi một hàm quá tải được gọi. • Khi hàm được gọi với kiểu đối số sai, các quy tắc chuyển đổi tự động của C++ gây ra tình trạng không xác định. Bản thân sự quá tải hàm ở ví dụ này tự nó không có tính không xác định. Ví dụ 4.2 // This program is ambiguous. #include void f(unsigned char c) { cout << c; } void f(char c) { cout << c; } int main() { f('c'); f(86); // which f() is called??? return 0; } Chương 4 Quá tải hàm 128 128 • Tính không xác định xảy ra do quá tải các hàm, trong đó có sự khác biệt duy nhất là một hàm sử dụng một tham số tham chiếu và hàm kia sử dụng tham số mặc định gọi bằng giá trị. Ví dụ 4.3 // An ambiguous program. #include int f(int a, int b) { return a+b; } // this is inherently ambiguous int f(int a, int &b) { return a-b; } int main() { int x=1, y=2; cout << f(x, y); // which version of f() is called??? return 0; } @ Lỗi biên dịch ở hàm f(int a, int &b) có dạng Error : 'f(int, int &)' cannot be distinguished from 'f(int, int)' Chương 4 Quá tải hàm 129 129 • Tính không xác định xảy ra do quá tải hàm, trong đó có một hay nhiều hàm được quá tải dùng một đối số mặc định. Ví dụ 4.4 // Ambiguity based on default arguments plus overloading. #include int f(int a) { return a*a; } int f(int a, int b = 0) { return a*b; } int main() { cout << f(10, 2); // calls f(int, int) cout << f(10); // ambiguous - call f(int) or f(int, int)??? return 0; } Chương 4 Quá tải hàm 130 130 V/ Tìm điạ chỉ của một hàm quá tải Trong ngôn ngữ C, để biết điạ chỉ một hàm, dùng con trỏ p trỏ đến hàm đó, chẳng hạn p = zap; // với hàm zap() Trong ngôn ngữ C++, vấn đề hơi phức tạp hơn bởi vì hàm có thể được quá tải. Cơ chế : dùng cách khai báo con trỏ xác định điạ chỉ của hàm quá tải nào sẽ thu được. Hàm có sự phù hợp khai báo là hàm có điạ chỉ được sử dụng. Ví dụ 5.1 /* Illustrate assigning function pointers to overloaded functions. */ #include // Output count number of spaces. void space(int count) { for( ; count; count--) cout << ' '; } // Output count number of chs. void space(int count, char ch) { for( ; count; count--) cout << ch; } int main() { // Create a pointer to void function with one int parameter. void (*fp1)(int); // Create a pointer to void function with one int parameter Chương 4 Quá tải hàm 131 131 // and one character parameter. void (*fp2)(int, char); fp1 = space; // gets address of space(int) fp2 = space; // gets address of space(int, char) fp1(22); // output 22 spaces cout << "|\n"; fp2(30, 'x'); // output 30 xs cout << "|\n"; return 0; } @ Khai báo con trỏ hàm phải phù hợp chính xác vơí một và chỉ một hàm quá tải. Nếu không, tính không xác định sẽ xảy ra và gây ra lỗi thời gian biên dịch. Bài tập V 1. Cho hai hàm quá tải. Tìm điạ chỉ của mỗi hàm int dif(int a, int b) { return a-b; } float dif(float a, float b) { return a-b; } Chương 4 Quá tải hàm 132 132 Bài tập chương 4 1. Hãy quá tải hàm tạo date() trong ví dụ 1.3, chương 4 để cho nó nhận một tham số kiểu time_t. 2. Tìm lỗi sai trong chương trình sau : class samp { int a; public: samp(int i) { a = i; } // ... }: // ... int main() { samp x, y(10); // ... } 3. Hãy tạo hàm reverse() nhận hai tham số. Tham số thứ nhất, gọi là str, là con trỏ trỏ tới chuỗi mà chuỗi này được đảo ngược khi trả về từ hàm. Tham số thứ hai gọi là count và nó chỉ rõ có bao nhiêu ký tự của chuỗi để đảo ngược. Hãy cho count một giá trị mặc định để báo cho reverse() đảo ngược toàn bộ chuỗi. 4. Tìm lỗi sai trong đoạn chương trình sau : void compute(double *num, int divisor=1); void compute(double *num); // ... compute(&x); 5. Hãy tạo hàm order() để nhận hai tham số tham chiếu nguyên. Nếu đối số thứ nhất lớn hơn đối số thứ hai, hãy đảo ngược hai đối số. Ngược lại, không tác động nào. Ví dụ Chương 4 Quá tải hàm 133 133 int x=1, y=0; order(x, y); 6. Tại sao hai hàm quá tải sau vốn không xác định ? int f(int a); int f(int &a); 7. Cho lớp sau, hãy bổ sung các hàm tạo cần thiết để cho cả hai khai báo trong main() đều đúng. class samp { int a; public: // add constructor functions ... int get_a() { return a; } }; int main() { samp ob(88); // init ob's a to 88 samp obarray[10]; // noninitialized 10-element array // ... } 8. Thực hiện quá tải hàm tạo đối với lớp sau đây sao cho các đối tượng không được khởi đầu cũng được tạo ra. class myclass { int x, y; public : myclass(int i, int j) {x= i; y =j;} // ... } 9. Qua bài tập 8, hãy chứng tỏ có thể không quá tải myclass() bằng cách dùng đối số mặc định. Chương 4 Quá tải hàm 134 134 10. Cho lớp sau đây, có thể cấp phát động một mảng các đối tượng này không ? class test { char *p; int *q; int count; public: test(char *x, int *y, int c) { p = x; q = y; count = c; } // ... };
File đính kèm:
- bai_giang_lap_trinh_huong_doi_tuong_tap_1_chuong_4_qua_tai_h.pdf