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

 

pdf32 trang | Chuyên mục: C/C++ | Chia sẻ: tuando | Lượt xem: 341 | Lượt tải: 0download
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:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_tap_1_chuong_4_qua_tai_h.pdf