Khai báo hàm
Khai báo hàm mô tả một nguyên mẫu mà không chỉ định phần thân hàm. Thay vì một khối chứa phần thân, một dấu chấm phẩy được đặt vào.
Khai báo là cần thiết cho trình biên dịch để nó có thể kiểm tra trong các đoạn mã tiếp theo xem hàm được gọi chính xác như thế nào bằng tên, truyền đối số vào nó và nhận kết quả.
Toàn bộ định nghĩa hàm (bao gồm phần thân) cũng là một khai báo, vì vậy không cần phải khai báo hàm bổ sung ngoài định nghĩa.
Ví dụ, khai báo của hàm Fibo
ở trên có thể trông như thế này.
int Fibo(const int n);
Khai báo và định nghĩa hàm riêng biệt được sử dụng khi xây dựng một chương trình từ nhiều tệp chứa mã nguồn: khi đó khai báo được thực hiện trong tệp tiêu đề với phần mở rộng mqh
(xem phần về chỉ thị tiền xử lý #include), tệp này được bao gồm trong các tệp nơi hàm được sử dụng, và định nghĩa hàm chỉ được triển khai trong một trong các tệp. Việc khớp chữ ký hàm trong khai báo và định nghĩa cung cấp sự bảo vệ chống lỗi. Nói cách khác, một khai báo duy nhất đảm bảo tính nhất quán của các thay đổi được thực hiện trên toàn bộ mã nguồn.
Nếu chúng ta khai báo một hàm và gọi nó ở đâu đó trong mã, nhưng không cung cấp định nghĩa hoàn toàn phù hợp cho nó, trình biên dịch sẽ báo lỗi: "function 'Name' must have a body" (hàm 'Tên' phải có phần thân). Điều này thường xảy ra khi có lỗi đánh máy hoặc không chính xác trong khai báo hoặc định nghĩa, cũng như trong quá trình thay đổi mã nguồn, khi một số sửa đổi đã được thực hiện, và phần còn lại có thể đã bị quên.
Nếu hàm được khai báo và không được sử dụng ở bất kỳ đâu, trình biên dịch cũng không yêu cầu định nghĩa của nó - phần tử như vậy đơn giản là bị "cắt bỏ" khỏi chương trình nhị phân.
Trong phần Câu lệnh khai báo/định nghĩa, chúng ta đã xem xét một ví dụ về hàm Init
(script StmtDeclaration.mq5
), được sử dụng để khởi tạo biến. Ở đó, đặc biệt, vấn đề đã được chứng minh rằng biến toàn cục k
không thể được định nghĩa trước hàm Init
, vì giá trị ban đầu của k
được lấy bằng cách gọi Init
. Trình biên dịch báo lỗi "'Init' is an unknown identifier" ('Init' là một định danh không xác định).
Bây giờ chúng ta biết rằng vấn đề như vậy có thể được giải quyết bằng khai báo. Trong script FuncDeclaration.mq5
, chúng ta đã thêm khai báo trước của hàm Init
trước biến k
, và để lại định nghĩa của Init
sau k
.
// khai báo trước
int Init(const int v);
// trước khi thêm khai báo trước ở trên
// ở đây có lỗi: 'Init' là một định danh không xác định
int k = Init(-1);
int Init(const int v)
{
Print("Init: ", v);
return v;
}
2
3
4
5
6
7
8
9
10
Bây giờ script biên dịch bình thường. Về mặt kỹ thuật, trong trường hợp này, chúng ta có thể đơn giản di chuyển hàm lên trên biến mà không cần khai báo trước. Chúng ta đã làm điều này để giải thích khái niệm. Tuy nhiên, có những trường hợp phụ thuộc lẫn nhau giữa các phần tử ngôn ngữ (ví dụ, các lớp), khi không thể thực hiện mà không có khai báo trước trong cùng một tệp.