Nạp Chồng Hàm
Thông thường, tên hàm thường phản ánh mục đích chính của nó. Theo quy tắc, các chương trình dễ đọc chứa nhiều identifiers được chọn lọc tốt. Đôi khi các hàm khác nhau được sử dụng cho cùng mục đích. Hãy xem xét, ví dụ, một hàm tính giá trị trung bình của một mảng số thực có độ chính xác kép và cùng hàm đó, nhưng hoạt động với một mảng số nguyên. Cả hai đều tiện lợi khi được gọi là AverageFromArray:
//+------------------------------------------------------------------+
//| Tính trung bình cho mảng kiểu double |
//+------------------------------------------------------------------+
double AverageFromArray(const double & array[],int size)
{
if(size<=0) return 0.0;
double sum=0.0;
double aver;
//---
for(int i=0;i<size;i++)
{
sum+=array[i]; // Tổng cho kiểu double
}
aver=sum/size; // Chỉ cần chia tổng cho số lượng
//---
Print("Tính trung bình cho mảng kiểu double");
return aver;
}
//+------------------------------------------------------------------+
//| Tính trung bình cho mảng kiểu int |
//+------------------------------------------------------------------+
double AverageFromArray(const int & array[],int size)
{
if(size<=0) return 0.0;
double aver=0.0;
int sum=0;
//---
for(int i=0;i<size;i++)
{
sum+=array[i]; // Tổng cho kiểu int
}
aver=(double)sum/size; // Chuyển tổng sang kiểu double và chia
//---
Print("Tính trung bình cho mảng kiểu int");
return aver;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Mỗi hàm chứa thông điệp đầu ra thông qua hàm Print():
Print("Tính trung bình cho mảng kiểu int");
Trình biên dịch chọn hàm cần thiết dựa trên kiểu và số lượng đối số. Quy tắc mà theo đó lựa chọn được thực hiện được gọi là signature matching algorithm
. Chữ ký là danh sách các kiểu được sử dụng trong khai báo hàm.
Ví dụ:
//+------------------------------------------------------------------+
//| Hàm bắt đầu chương trình script |
//+------------------------------------------------------------------+
void OnStart()
{
//---
int a[5]={1,2,3,4,5};
double b[5]={1.1,2.2,3.3,4.4,5.5};
double int_aver=AverageFromArray(a,5);
double double_aver=AverageFromArray(b,5);
Print("int_aver = ",int_aver," double_aver = ",double_aver);
}
//--- Kết quả của script
// Tính trung bình cho mảng kiểu int
// Tính trung bình cho mảng kiểu double
// int_aver= 3.00000000 double_aver= 3.30000000
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Nạp chồng hàm là quá trình tạo ra nhiều hàm với cùng tên nhưng các tham số khác nhau. Điều này có nghĩa là trong các biến thể nạp chồng của một hàm, số lượng đối số và/hoặc kiểu của chúng phải khác nhau. Một biến thể hàm cụ thể được chọn dựa trên sự tương ứng giữa danh sách đối số khi gọi hàm với danh sách tham số trong khai báo hàm.
Khi một hàm nạp chồng được gọi, trình biên dịch phải có một thuật toán để chọn hàm phù hợp. Thuật toán thực hiện lựa chọn này phụ thuộc vào castings của các kiểu nào có mặt. Sự tương ứng tốt nhất phải là duy nhất. Một hàm nạp chồng phải là sự khớp tốt nhất trong số tất cả các biến thể khác cho ít nhất một đối số. Đồng thời, nó phải khớp với tất cả các đối số khác không tệ hơn các biến thể khác.
Dưới đây là thuật toán khớp cho mỗi đối số.
Thuật Toán Chọn Hàm Nạp Chồng
- Sử dụng khớp nghiêm ngặt (nếu có thể).
- Thử tăng kiểu tiêu chuẩn.
- Thử ép kiểu tiêu chuẩn.
Tăng kiểu tiêu chuẩn tốt hơn các chuyển đổi tiêu chuẩn khác. Tăng kiểu là việc chuyển đổi từ float
sang double
, từ bool
, char
, short
hoặc enum
sang int
. Ép kiểu của mảng các integer types tương tự cũng thuộc về ép kiểu. Các kiểu tương tự bao gồm: bool, char, uchar, vì cả ba đều là số nguyên một byte; số nguyên hai byte short và ushort; số nguyên 4 byte int, uint, và color; long, ulong, và datetime.
Tất nhiên, khớp nghiêm ngặt là tốt nhất. Để đạt được sự nhất quán như vậy, có thể sử dụng typecasting. Trình biên dịch không thể xử lý các tình huống mơ hồ. Do đó, bạn không nên dựa vào sự khác biệt tinh tế của kiểu và các chuyển đổi ngầm định làm cho hàm nạp chồng trở nên không rõ ràng.
Nếu bạn nghi ngờ, hãy sử dụng chuyển đổi rõ ràng để đảm bảo tuân thủ nghiêm ngặt.
Ví dụ về các hàm nạp chồng trong MQL5 có thể thấy trong ví dụ về hàm ArrayInitialize().
Quy tắc nạp chồng hàm áp dụng cho overload of class methods.
Nạp chồng các hàm hệ thống được phép, nhưng cần chú ý rằng trình biên dịch có thể chọn chính xác hàm cần thiết. Ví dụ, chúng ta có thể nạp chồng hàm hệ thống MathMax() theo 4 cách khác nhau, nhưng chỉ hai biến thể là đúng.
Ví dụ:
// 1. Nạp chồng được phép - hàm khác với hàm MathMax() tích hợp sẵn về số lượng tham số
double MathMax(double a,double b,double c);
// 2. Nạp chồng không được phép!
// số lượng tham số khác nhau, nhưng tham số cuối có giá trị mặc định
// điều này dẫn đến việc che giấu hàm hệ thống khi gọi, điều này là không chấp nhận được
double MathMax(double a,double b,double c=DBL_MIN);
// 3. Nạp chồng được phép - nạp chồng bình thường theo kiểu của tham số a và b
double MathMax(int a,int b);
// 4. Nạp chồng không được phép!
// số lượng và kiểu của tham số giống với hàm gốc double MathMax(double a,double b)
int MathMax(double a,double b);
2
3
4
5
6
7
8
9
10
11
12
13
14
Xem thêm