Destructors
Trong chương về cấu trúc, chúng ta đã học về destructors (xem phần về Constructors and destructors). Hãy tóm tắt ngắn gọn: một destructor là một phương thức được gọi khi một đối tượng bị hủy. Destructor có cùng tên với lớp nhưng được thêm tiền tố bằng ký tự dấu ngã (~
). Destructor không trả về giá trị và không có bất kỳ tham số nào. Một lớp chỉ có thể có một destructor.
Ngay cả khi lớp không có destructor hoặc destructor trống, trình biên dịch sẽ ngầm thực hiện "thu gom rác" cho các loại trường sau: chuỗi, mảng động và đối tượng tự động.
Thông thường, destructor được đặt trong phần public
của lớp, tuy nhiên, trong một số trường hợp cụ thể, nhà phát triển có thể di chuyển nó vào nhóm thành viên private
hoặc protected
. Một destructor private
hoặc protected
sẽ không cho phép bạn khai báo một biến tự động của lớp này trong mã. Tuy nhiên, chúng ta sẽ thấy dynamic object creation một chút sau, và đối với chúng, một hạn chế như vậy có thể có ý nghĩa.
Đặc biệt, một số đối tượng có thể được triển khai theo cách mà chúng phải tự xóa khi chúng không còn cần thiết nữa (khái niệm xác định nhu cầu có thể khác nhau). Nói cách khác, trong khi các đối tượng được sử dụng bởi bất kỳ phần nào của chương trình, chúng tồn tại, và ngay khi nhiệm vụ hoàn thành, chúng sẽ tự hủy (một destructor private
để lại khả năng xóa đối tượng khỏi các phương thức lớp).
Đối với các lập trình viên C++ có kinh nghiệm, đáng chú ý là destructors luôn là virtual
trong MQL5 (thêm về các phương thức ảo sẽ được đề cập trong phần về Virtual methods (virtual and override)). Yếu tố này không ảnh hưởng đến cú pháp của mô tả.
Trong ví dụ về chương trình vẽ, về mặt kỹ thuật, một destructor có thể không cần thiết cho các hình dạng. Tuy nhiên, để theo dõi trình tự các lệnh gọi đến constructors và destructors, chúng ta sẽ đưa vào một lệnh gọi. Hãy bắt đầu với một phác thảo đơn giản "in" tên đầy đủ của phương thức:
class Shape
{
...
~Shape()
{
Print(__FUNCSIG__);
}
};
2
3
4
5
6
7
8
Chúng ta sẽ sớm thêm vào phương thức này và các phương thức khác để có thể phân biệt một thể hiện của đối tượng với một thể hiện khác.
Xem xét ví dụ sau. Một cặp đối tượng Shape
được mô tả trong hai ngữ cảnh khác nhau: toàn cục (bên ngoài các hàm) và cục bộ (bên trong OnStart
). Constructor đối tượng toàn cục sẽ được gọi sau khi script được tải và trước khi OnStart
được gọi, và destructor sẽ được gọi trước khi script được dỡ tải. Constructor đối tượng cục bộ sẽ được gọi trong dòng với định nghĩa biến, và destructor sẽ được gọi khi khối mã chứa định nghĩa biến thoát, trong trường hợp này là hàm OnStart
.
// constructor và destructor toàn cục có liên quan đến việc tải và dỡ script
Shape global;
// tham chiếu đối tượng không tạo bản sao và không ảnh hưởng đến vòng đời
void ProcessShape(Shape &shape)
{
// ...
}
void OnStart()
{
// ...
Shape local; // <- lệnh gọi constructor cục bộ
// ...
ProcessShape(local);
// ...
} // <- lệnh gọi destructor cục bộ
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Việc truyền một đối tượng theo tham chiếu đến các hàm khác không tạo ra các bản sao của nó và không gọi constructor và destructor.