Tải bản đầy đủ (.pdf) (10 trang)

Định nghĩa chồng các hàm (overloading)

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (99.77 KB, 10 trang )

Định nghĩa chồng các hàm (overloading)

Định nghĩa chồng các hàm
(overloading)
Bởi:
Phạm Văn Ất

Khái niệm về định nghĩa chồng
Định nghĩa chồng (hay còn gọi sự tải bội) các hàm là dùng cùng một tên để định nghĩa
các hàm khác nhau. Đây là một mở rộng rất có ý nghĩa của C++.
Như đã biết, trong C và các ngôn ngữ khác (như PASCAL, FOXPRO,...) mỗi hàm đều
phải có một tên phân biệt. Đôi khi đây là một sự hạn chế lớn, vì phải dùng nhiều hàm
khác nhau để thực hiện cùng một công việc. Ví dụ để lấy giá trị tuyệt đối trong C cần
dùng tới 3 hàm khác nhau:
int abs(int i); // Lấy giá trị tuyệt đối giá trị kiểu int
longt labs(longt l); // Lấy giá trị tuyệt đối giá trị kiểu
long double fabs(double d); // Lấy giá trị tuyệt đối giá
trị kiểu double
Nhờ khả năng định nghĩa chồng, trong C++ có thể dùng chung một tên cho cả 3 hàm
trên như sau:
int abs(int i) ; // Lấy giá trị tuyệt đối giá trị kiểu int
longt abs(longt l) ; // Lấy giá trị tuyệt đối giá trị kiểu
long double abs(double d) ; // Lấy giá trị tuyệt đối giá
trị kiểu double

Yêu cầu về các hàm định nghĩa chồng
Khi dùng cùng một tên để định nghĩa nhiều hàm, Trình biên dịch C++ sẽ dựa vào sự
khác nhau về tập đối của các hàm này để đổi tên các hàm. Như vậy, sau khi biên dịch
mỗi hàm sẽ có một tên khác nhau.

1/10




Định nghĩa chồng các hàm (overloading)

Từ đó cho thấy: các hàm được định nghĩa trùng tên phải có tập đối khác nhau (về số
lượng hoặc kiểu). Nếu 2 hàm hoàn toàn trùng tên và trùng đối thì Trình biên dịch sẽ
không có cách nào phân biệt được. Ngay cả khi 2 hàm này có kiểu khác nhau thì Trình
biên dịch vẫn báo lỗi. Ví dụ sau xây dựng 2 hàm cùng có tên là f và cùng có một đối
nguyên a, nhưng kiểu hàm khác nhau. Hàm thứ nhất kiểu nguyên (trả về a*a), hàm thứ
hai kiểu void (in giá trị a). Chương trình sẽ bị thông báo lỗi khi biên dịch (bạn hãy thử
xem sao)
#include <conio.h> #include <iostream.h> int f(int a);
void f(int a); int f(int a) { return a*a; } void f(int a)
{ cout << "\n " << a ; } void main() { int b=f(5); f(b);
getch(); }

Sử dụng các hàm định nghĩa chồng
Khi gặp một lời gọi, Trình biên dịch sẽ căn cứ vào số lượng và kiểu của các tham số để
gọi hàm có đúng tên và đúng bộ đối số tương ứng. Ví dụ:
abs(123); // Tham số kiểu int, gọi hàm int abs(int i) ;
abs(123L); // Tham số kiểu long, gọi hàm long abs(long l);
abs(3.14); //Tham số kiểu double, gọi hàm double
abs(double d);
Khi không có hàm nào có bộ đối cùng kiểu với bộ tham số (trong lời gọi), thì Trình biên
dịch sẽ chọn hàm nào có bộ đối gần kiểu nhất (phép chuyển kiểu dễ dàng nhất). Ví dụ:
abs(‘A’) ; // Tham số kiểu char, gọi hàm int abs(int i) ;
abs(3.14F); // Tham số kiểu float, gọi hàm double
abs(double d);

Nên sử dụng phép định nghĩa chồng các hàm như thế nào

Như đã nói ở trên, khi xây dựng cũng như sử dụng các hàm trùng tên, Trình biên dịch
C++ đã phải suy đoán và giải quyết nhiều trường hợp khá nhập nhằng. Vì vậy không
nên lạm dụng quá đáng khả năng định nghĩa chồng, vì điều đó làm cho chương trình
khó kiểm soát và dễ dẫn đến sai sót. Việc định nghĩa chồng sẽ hiệu quả hơn nếu được
sử dụng theo các lời khuyên sau:
+ Chỉ nên định nghĩa chồng các hàm thực hiện những công việc như nhau nhưng trên
các đối tượng có kiểu khác nhau. Ví dụ trong chương trình cần xây dựng các hàm: cộng
2 ma trận vuông kiểu double, cộng 2 ma trận vuông kiểu int, cộng 2 ma trân chữ nhật

2/10


Định nghĩa chồng các hàm (overloading)

kiểu double, cộng 2 ma trận chữ nhật kiểu int, thì 4 hàm trên nên định nghĩa chồng (đặt
cùng tên).
+ Nên dùng các phép chuyển kiểu (nếu cần) để bộ tham số trong lời gọi hoàn toàn trùng
kiểu với bộ đối số của một hàm được định nghĩa chồng. Vì như thế mới tránh được sự
nhập nhằng cho Trình biên dịch và Trình biên dịch sẽ chọn đúng hàm cần gọi.

Lấy địa chỉ các hàm trùng tên
Giả sử có 4 hàm đều có tên là tinh_max được khai báo như sau:
int tinh_max(int a, int b, int c) ; // Max của 3 số nguyên
double tinh_max(double a, double b, double c); // Max của
3 số // thực int tinh_max(int *a, int n) ; // Max của một
dẫy số nguyên double tinh_max(double *a, int n) ; //Max
của một dẫy số thực
Vấn đề đặt ra là làm thế nào lấy được địa chỉ của mỗi hàm. Câu trả lời như sau:
Để lấy địa chỉ của một hàm, ta khai báo một con trỏ hàm có kiểu và bộ đối như hàm cần
lấy địa chỉ. Sau đó gán tên hàm cho con trỏ hàm. Ví dụ:

int (*f1)(int , int, int ); f1 = tinh_max ; // Lấy địa chỉ
của hàm thứ nhất double (*f2)(double , double, double); f2
= tinh_max ; // Lấy địa chỉ của hàm thứ hai int (*f3)(int
*, int ); f3 = tinh_max ; // Lấy địa chỉ của hàm thứ ba
double (*f4)(double *, int ); f4 = tinh_max ; // Lấy địa
chỉ của hàm thứ tư

Các ví dụ
Chương trình giải bài toán tìm max của một dẫy số nguyên và max của một dẫy số thực.
Trong chươmg trình có 6 hàm. Hai hàm dùng để nhập dẫy số nguyên và dẫy số thực có
tên chung là nhapds. Bốn hàm: tính max 2 số nguyên, tính max 2 số thực, tính max của
dẫy số nguyên, tính max của dẫy số thực được đặt chung một tên là max.
#include <conio.h>
#include <iostream.h>
#include <iomanip.h>

3/10


Định nghĩa chồng các hàm (overloading)

void nhapds(int *x, int n);
void nhapds(double *x, int n);
int max(int x, int y);
double max(double x, double y);
int max(int *x, int n);
double max(double *x, int n);
void nhapds(int *x, int n)
{
for (int i=1;i<=n;++i)

{
cout << "Phan tu " << i << " = " ;
cin >> x[i] ;
}
}
void nhapds(double *x, int n)
{
for (int i=1;i<=n;++i)
{
cout << "Phan tu " << i << " = " ;
cin >> x[i] ;
}
}
4/10


Định nghĩa chồng các hàm (overloading)

int max(int x, int y)
{
return x>y?x:y ;
}
double max(double x, double y)
{
return x>y?x:y ;
}
int max(int *x, int n)
{
int s=x[1];
for (int i=2;i<=n;++i)

s = max(s,x[i]);
return s;
}
double max(double *x, int n)
{
double s=x[1];
for (int i=2;i<=n;++i)
s = max(s,x[i]);
return s;
}
5/10


Định nghĩa chồng các hàm (overloading)

void main()
{
int a[20] , n , ni, nd, maxi ;
double x[20] , maxd ;
clrscr();
cout << "\nSo phan tu nguyen ni = " ;
cin >> ni ;
cout << "Nhap day so nguyen\n " ;
nhapds(a,ni);
cout << "\nSo phan tu thuc nd = " ;
cin >> nd ;
cout << "Nhap day so thuc\n " ;
nhapds(x,nd);
maxi = max(a,ni);
maxd = max(x,nd);

cout << "\nMax cua day nguyen = " << maxi ;
cout << "\nMax cua day thuc = " << maxd ;
getch();
}
Chương trình sau thực hiện phép nhân ma trận:
D = A*B*C

6/10


Định nghĩa chồng các hàm (overloading)

trong đó A, B là các ma trận vuông, C là ma trận chữ nhật. Trong chương trình có 3 cặp
hàm trùng tên để thực hiện 3 nhiệm vụ (nhưng trên 2 đối tượng khác nhau là ma trận
vuông và chữ nhật): Nhập ma trận, nhân 2 ma trận và in ma trân.
#include <conio.h>
#include <iostream.h>
#include <iomanip.h>
typedef int MT[20][20];
void nhapmt(MT a,char *ten, int m, int n);
void inmt(MT a,char *ten, int m, int n);
void nhanmt(MT a,MT b, MT c, int m, int n, int p);
void nhapmt(MT a,char *ten, int n);
void inmt(MT a,char *ten, int n);
void nhanmt(MT a,MT b, MT c, int n);
void nhapmt(MT a, char *ten, int m, int n)
{
for (int i=1;i<=m;++i)
for (int j=1;j<=n;++j)
{

cout << "\n" << ten <<"[" << i << "," << j << "]= " ;
cin >> a[i][j];
}
}
void nhapmt(MT a,char *ten, int n)
7/10


Định nghĩa chồng các hàm (overloading)

{
nhapmt(a,ten,n,n) ;
}
void inmt(MT a,char *ten, int m, int n)
{
cout << "\nMa tran: " << ten;
for (int i=1;i<=m;++i)
{
cout << "\n" ;
for (int j=1;j<=n;++j)
cout << setw(6) << a[i][j];
}
}
void inmt(MT a,char *ten, int n)
{
inmt(a,ten,n,n) ;
}
void nhanmt(MT a,MT b, MT c, int m, int n, int p)
{
for (int i=1;i<=m;++i)

for (int j=1;j<=p;++j)
{
8/10


Định nghĩa chồng các hàm (overloading)

c[i][j]=0;
for (int k=1;k<=n;++k)
c[i][j] += a[i][k] * b[k][j];
}
}
void nhanmt(MT a,MT b, MT c, int n)
{
nhanmt(a,b,c,n,n, n) ;
}
void main()
{
MT a,b,c,d; // d= abc
MT u;
clrscr();
nhapmt(a,"A",2);
nhapmt(b,"B",2);
nhapmt(c,"C",2,3);
nhanmt(a,b,u,2);
nhanmt(u,c,d,2,2,3);
inmt(a,"A",2);
inmt(b,"B",2);
inmt(u,"U = A*B",2);
9/10



Định nghĩa chồng các hàm (overloading)

inmt(c,"C",2,3);
inmt(d,"D = U*C",2,3);
getch();
}

10/10



×