Классы mql взаимодействие
4 февраля 2021 г. 9:46
Приведу простой пример взаимодействия классов в mql4, их атрибутов, конструкторов и копи-конструкторов copy constructor. Особенно пример будет полезен тем, кто никогда не сталкивался с C-подобными языками программирования (C++, C#, java).
Сразу сообщу, что в этой статье не будут расписаны все моменты работы с классами. Только простой пример для того, чтобы быстро начать использовать классы для более гибкого написания кода. Полный текст программы в конце статьи.
Также я не придерживался принятого стиля написания кода mql, так как я привык оформлять код как в python и считаю принятое оформление кода менее читабельным. Да простят меня mql-разработчики!
Допустим, в некоторые переменные нужно сохранить данные о сотрудниках некоторой компании, а затем вывести имя директора, например так:
Employee mike("Mike", "Director");
Employee denis("Denis", "Designer");
company.add_employee(mike);
company.add_employee(denis);
director = company.get_director();
Print("Director name is " + director.name);
Можно сохранять данную информацию проще. Во второй версии программы вы увидите, как это можно сделать.
Код программы находится на github:
https://github.com/vivazzi/mql_examples/blob/master/classes/Classes.mq4
1 версия
Создадим класс Employee, который сохраняет имя сотрудника в поле name и его должность в поле post:
class Employee {
public:
string name;
string post;
// По умолчанию, объявленные переменные имеют значение NULL, поэтому нет необходимости
// в конструкторе без параметров к каждой переменной присваивать NULL. Но сам конструктор без параметров нужно добавить.
// Далее вы увидите зачем нам конструктор без параметров и зачем я рассказал про NULL
Employee(){};
// при создании объекта класса Employee будем сохранять имя (name) и должность (post)
Employee(string _name, string _post) {
name = _name;
post = _post;
};
// данная конструкция, так называемая copy constructor, позволяет создавать копию объекта.
// Это позволяет не только копировать объекты, но и различным сторонним функциям других классов возвращать объект класса Employee
Employee::Employee(const Employee &_employee) {
name = _employee.name;
post = _employee.post;
}
};
Employee employees[2]; // объявим, что у нас два сотрудника в компании. Позже улучшим код для динамического добавления сотрудников
Хочу заметить, что в копи-конструкторе Employee::Employee(const Employee &_employee) приходится снова дублировать логику работы конструктора, иначе в возвращаемом (копируемом) объекте не присвоются поля объекта класса. Давайте теперь ниже опишем класс Company, чтобы лучше понять, зачем нам копи-конструктор:
class Company {
public:
Employee get_director() {
for (int i=0; i < ArraySize(employees); i++) {
// если у сотрудника должность Директор, то возвратить данного сотрудника
if (employees[i].post == "Director") return employees[i];
}
return Employee();
}
};
Заметьте, если бы у нас не было копи-конструктора Employee, то компилятор выдал бы ошибку:
error: object of cannot be returned, copy constructor not found
Обратите внимание, что в mql4 нет возможности возвратить NULL в случае если совпадении по должности Director нет, так как язык mql4 является строго типизированным. Поэтому, мы должны возвратить "пустого" сотрудника, то есть объект класса Employee без значений в полях name и post, а если точнее говорить, то со значениями NULL. Для этого в классе Employee добавлен конструктор без тела , а в функции get_director(), если нет сотрудника с указанной должностью, то возвращаем Employee с пустыми скобками: так автоматически создастся Employee со значениями NULL в полях name и post. Это как раз нам и нужно, например, чтобы сравнить, есть ли у Employee имя, и если есть, то производим дальнейшую обработку, например, показываем имя через Print. Вот оставшаяся часть кода, где можно теперь записать и использовать наши объекты классов:
int OnInit(){
employees[0] = Employee("Mike", "Director");
employees[1] = Employee("Denis", "Designer");
Company company;
Employee director;
director = company.get_director();
if (director.name != NULL) Print("Director name is " + director.name);
else Print("There is not director in company");
// можно и не создавать переменную director, а использовать company.get_director().name:
Print("Director name is " + company.get_director().name);
return(INIT_SUCCEEDED);
}
Итоговый вариант кода:
class Employee {
public:
string name;
string post;
Employee(){};
Employee(string _name, string _post) {
name = _name;
post = _post;
};
Employee::Employee(const Employee &_employee) {
name = _employee.name;
post = _employee.post;
}
};
Employee employees[2];
class Company {
public:
Employee get_director() {
for (int i=0; i < ArraySize(employees); i++) {
// если у сотрудника должность Директор, то возвратить данного сотрудника
if (employees[i].post == "Director") return employees[i];
}
return Employee();
}
};
int OnInit(){
employees[0] = Employee("Mike", "Director");
employees[1] = Employee("Denis", "Designer");
Company company;
Employee director;
director = company.get_director();
if (director.name != NULL) Print("Director name is " + director.name);
else Print("There is not director in company");
Print("Director name is " + company.get_director().name);
return(INIT_SUCCEEDED);
}Версия 2
Теперь, когда код первой версии работает и наглядно понятен, можно сделать более гибкую версию записи данных:
class Employee {
public:
string name;
string post;
Employee(){};
Employee(string _name, string _post) {
name = _name;
post = _post;
};
Employee::Employee(const Employee &_employee) {
name = _employee.name;
post = _employee.post;
}
};
class Company {
public:
Employee employees[];
void set_employees(Employee &_employees[]){
ArrayResize(employees, ArraySize(_employees));
for (int i=0; i < ArraySize(employees); i++) {
employees[i] = _employees[i];
}
}
void add_employee(Employee &_employee){
ArrayResize(employees, ArraySize(employees) + 1);
employees[ArraySize(employees) - 1] = _employee;
}
void add_employee(string name, string post){
ArrayResize(employees, ArraySize(employees) + 1);
employees[ArraySize(employees) - 1] = Employee(name, post);
}
Employee get_employee_by_post(string post) {
for (int i=0; i < ArraySize(employees); i++) {
if (employees[i].post == post) return employees[i];
}
return Employee();
}
Employee get_director() {
return get_employee_by_post("Director");
}
int employee_number() {
return ArraySize(employees);
}
string display_employees() {
string res = "";
for (int i=0; i < ArraySize(employees); i++) {
res += employees[i].name;
if (i < ArraySize(employees) - 1) res += ", ";
}
return res;
}
};
int OnInit(){
Company company;
// можем добавлять сотрудников, передав массив сотрудников
Employee employees[2];
employees[0] = Employee("Alla", "Manager");
employees[1] = Employee("Bella", "Manager");
company.set_employees(employees);
// или можем добавить одного сотрудника
Employee nataly("Nataly", "Manager");
company.add_employee(nataly);
// или можно добавить сотудников через передачу аргументов name и post
company.add_employee("Mike", "Director");
company.add_employee("Denis", "Designer");
Print("Number of employees is " + (string)company.employee_number() + ": " + company.display_employees());
Print("Director name is " + company.get_director().name);
Employee dancer;
dancer = company.get_employee_by_post("Dancer");
if (dancer.name != NULL) Print("Dancer name is " + dancer.name);
else Print("There is not dancer in company");
return(INIT_SUCCEEDED);
}
Во втором варианте я показал различные способы добавления сотрудников в компанию, а также вывод информации о сотрудниках. Поиграйтесь с примером, чтобы лучше понять, как работают классы на mql4.
Также хочу заметить, что это не самый оптимизированный код. Также он не особо удобен с точки зрения архитектуры программы, но так лучше понять классы на начальном уровне.
Код программы находится на github:
https://github.com/vivazzi/mql_examples/blob/master/classes/Classes.mq4
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0