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

