Thành viên tĩnh của Lớp/Cấu trúc
Thành viên tĩnh
Các thành viên của một lớp có thể được khai báo bằng cách sử dụng bộ sửa đổi lớp lưu trữ static. Những thành viên dữ liệu này được chia sẻ bởi tất cả các thể hiện của lớp này và được lưu trữ ở một nơi duy nhất. Các thành viên dữ liệu không tĩnh được tạo ra cho mỗi biến đối tượng của lớp.
Việc không thể khai báo các thành viên tĩnh của một lớp sẽ dẫn đến việc cần phải khai báo các dữ liệu này ở cấp độ toàn cục của chương trình. Điều này sẽ phá vỡ mối quan hệ giữa dữ liệu và lớp của chúng, và không phù hợp với mô hình cơ bản của OOP - kết hợp dữ liệu và các phương thức xử lý chúng trong một lớp. Thành viên tĩnh cho phép dữ liệu lớp không đặc thù cho một thể hiện cụ thể tồn tại trong phạm vi lớp.
Vì một thành viên tĩnh của lớp không phụ thuộc vào thể hiện cụ thể, cách tham chiếu đến nó như sau:
class_name::variable
trong đó class_name
là tên của lớp, và variable
là tên của thành viên lớp.
Như bạn thấy, để truy cập thành viên tĩnh của một lớp, toán tử phân giải ngữ cảnh :: được sử dụng. Khi bạn truy cập một thành viên tĩnh trong các phương thức của lớp, toán tử ngữ cảnh là tùy chọn.
Thành viên tĩnh của một lớp phải được khởi tạo rõ ràng với giá trị mong muốn. Để làm điều này, nó phải được khai báo và khởi tạo trong phạm vi toàn cục. Thứ tự khởi tạo các thành viên tĩnh sẽ tương ứng với thứ tự khai báo của chúng trong phạm vi toàn cục.
Ví dụ, chúng ta có một lớp CParser
được sử dụng để phân tích văn bản, và chúng ta cần đếm tổng số từ và ký tự đã xử lý. Chúng ta chỉ cần khai báo các thành viên lớp cần thiết là tĩnh và khởi tạo chúng ở cấp độ toàn cục. Sau đó, tất cả các thể hiện của lớp sẽ sử dụng các bộ đếm chung cho từ và ký tự.
//+------------------------------------------------------------------+
//| Lớp "Trình phân tích văn bản" |
//+------------------------------------------------------------------+
class CParser
{
public:
static int s_words;
static int s_symbols;
//--- Hàm tạo và hàm hủy
CParser(void);
~CParser(void){};
};
...
//--- Khởi tạo các thành viên tĩnh của lớp Parser ở cấp độ toàn cục
int CParser::s_words=0;
int CParser::s_symbols=0;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Một thành viên tĩnh của lớp có thể được khai báo với từ khóa const
. Các hằng số tĩnh như vậy phải được khởi tạo ở cấp độ toàn cục với từ khóa const
:
//+------------------------------------------------------------------+
//| Lớp "Ngăn xếp" để lưu trữ dữ liệu đã xử lý |
//+------------------------------------------------------------------+
class CStack
{
public:
CStack(void);
~CStack(void){};
...
private:
static const int s_max_length; // Dung lượng tối đa của ngăn xếp
};
//--- Khởi tạo hằng số tĩnh của lớp CStack
const int CStack::s_max_length=1000;
2
3
4
5
6
7
8
9
10
11
12
13
14
Con trỏ this
Từ khóa this biểu thị một con trỏ được khai báo ngầm định tới chính nó – tới một thể hiện cụ thể của lớp, trong ngữ cảnh mà phương thức được thực thi. Nó chỉ có thể được sử dụng trong các phương thức không tĩnh của lớp. Con trỏ this
là một thành viên không tĩnh ngầm định của bất kỳ lớp nào.
Trong các hàm tĩnh, bạn chỉ có thể truy cập các thành viên/phương thức tĩnh của một lớp.
Phương thức tĩnh
Trong MQL5, các hàm thành viên kiểu static có thể được sử dụng. Bộ sửa đổi static
phải đứng trước kiểu trả về của hàm trong khai báo bên trong một lớp.
class CStack
{
public:
//--- Hàm tạo và hàm hủy
CStack(void){};
~CStack(void){};
//--- Dung lượng tối đa của ngăn xếp
static int Capacity();
private:
int m_length; // Số lượng phần tử trong ngăn xếp
static const int s_max_length; // Dung lượng tối đa của ngăn xếp
};
//+------------------------------------------------------------------+
//| Trả về số lượng phần tử tối đa để lưu trữ trong ngăn xếp |
//+------------------------------------------------------------------+
int CStack::Capacity(void)
{
return(s_max_length);
}
//--- Khởi tạo hằng số tĩnh của lớp CStack
const int CStack::s_max_length=1000;
//+------------------------------------------------------------------+
//| Hàm khởi động chương trình script |
//+------------------------------------------------------------------+
void `OnStart`()
{
//--- khai báo biến kiểu CStack
CStack stack;
//--- gọi phương thức tĩnh của đối tượng
`Print`(`"CStack.s_max_length="`,stack.Capacity());
//--- nó cũng có thể được gọi theo cách sau, vì phương thức là tĩnh và không yêu cầu sự hiện diện của đối tượng
`Print`(`"CStack.s_max_length="`,CStack::Capacity());
}
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
Phương thức với bộ sửa đổi const
được gọi là hằng và không thể sửa đổi các thành viên ngầm định của lớp của nó. Việc khai báo các hàm hằng của một lớp và các tham số hằng được gọi là kiểm soát const-correctness
. Thông qua kiểm soát này, bạn có thể chắc chắn rằng trình biên dịch sẽ đảm bảo tính nhất quán của các giá trị của đối地上
Phương thức với bộ sửa đổi const
được đặt sau danh sách đối số trong khai báo lớp. Định nghĩa ngoài lớp cũng nên bao gồm bộ sửa đổi const
:
//+------------------------------------------------------------------+
//| Lớp "Hình chữ nhật" |
//+------------------------------------------------------------------+
class CRectangle
{
private:
double m_width; // Chiều rộng
double m_height; // Chiều cao
public:
//--- Hàm tạo và hàm hủy
CRectangle(void):m_width(0),m_height(0){};
CRectangle(const double w,const double h):m_width(w),m_height(h){};
~CRectangle(void){};
//--- Tính diện tích
double Square(void) const;
static double Square(const double w,const double h);// { return(w*h); }
};
//+------------------------------------------------------------------+
//| Trả về diện tích của đối tượng "Hình chữ nhật" |
//+------------------------------------------------------------------+
double CRectangle::Square(void) const
{
return(Square(m_width,m_height));
}
//+------------------------------------------------------------------+
//| Trả về tích của hai biến |
//+------------------------------------------------------------------+
static double CRectangle::Square(const double w,const double h)
{
return(w*h);
}
//+------------------------------------------------------------------+
//| Hàm khởi động chương trình script |
//+------------------------------------------------------------------+
void `OnStart`()
{
//--- Tạo một hình chữ nhật rect với các cạnh bằng 5 và 6
CRectangle rect(5,6);
//--- Tìm diện tích hình chữ nhật bằng phương thức hằng
`PrintFormat`(`"rect.Square()=%.2f"`,rect.Square());
//--- Tìm tích của các số bằng phương thức tĩnh của lớp CRectangle
`PrintFormat`(`"CRectangle::Square(2.0,1.5)=%f"`,CRectangle::Square(2.0,1.5));
}
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
37
38
39
40
41
42
43
Một lập luận bổ sung ủng hộ việc sử dụng kiểm soát tính hằng là thực tế rằng trong trường hợp này, trình biên dịch tạo ra một tối ưu hóa đặc biệt, ví dụ, đặt một đối tượng hằng trong bộ nhớ chỉ đọc.
Hàm tĩnh không thể được xác định với bộ sửa đổi const
, vì bộ sửa đổi này đảm bảo tính hằng của các thành viên thể hiện khi gọi hàm này. Nhưng, như đã đề cập ở trên, hàm tĩnh không thể truy cập các thành viên không tĩnh của lớp.
Xem thêm