Классы 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