Разбить класс на mqh и mq5.

 
Возможно ли каким то образом, нормально разбивать код на mqh и mq5 по аналогии с hpp и cpp? Крайне неудобно иметь обьявление класса и его код в одном mqh файле. Понятно что в MQL5 нет понятия обьектных файлов для каждого mq5 и собираются они все в кучу, но хотя бы не для скорости сборки, а для удобства это можно как то сделать?
 

Можно в стиле Java/C# весь класс оформить.

Разделение в С-стиле нужно ТОЛЬКО при публикации закрытой библиотеки.

 
Скорее всего, можно сделать просто два mqh файла. В первом только описание класса, во втором - подключаем первый и пишем реализацию методов класса. Только в другие файлы для использования готового класса надо будет подключать второй файл. В таком варианте, скорее всего будут свои неудобства, но если надо, то можно такое разделение организовать.
 
DrSky:
Возможно ли каким то образом, нормально разбивать код на mqh и mq5 по аналогии с hpp и cpp? Крайне неудобно иметь обьявление класса и его код в одном mqh файле. Понятно что в MQL5 нет понятия обьектных файлов для каждого mq5 и собираются они все в кучу, но хотя бы не для скорости сборки, а для удобства это можно как то сделать?

Конечно можно, я так пишу сам, удобно

 

У меня все оформлено через классы, которые лежат в *.mqh. Общие функции завернуты в классы, как статические методы. Классы разбиты по темам.

Структура Include/Проект

Например, кусок файла d:\Project\MQL5\Include\Cayman\UFile.mqh

#property copyright "Copyright 2020, Malik Arykov"
#property link "www.cayman-pro.ga"

#include <Arrays/ArrayString.mqh>

// флаги функции FileOpen
#define FILE_READ_UTF8 (int)(FILE_SHARE_READ|FILE_ANSI)
#define FILE_WRITE_UTF8 (int)(FILE_READ|FILE_WRITE|FILE_ANSI)
#define FILE_READ_UNICODE (int)(FILE_SHARE_READ|FILE_UNICODE)
#define FILE_WRITE_UNICODE (int)(FILE_READ|FILE_WRITE|FILE_UNICODE)

// -----------------------------------------------------------------------------
// Файловые функции
// -----------------------------------------------------------------------------
class UFile {
public:
    static bool IsDirectory(string path);
    static string Parent(string path);
    static string FileName(string path);
    static string FileNameWithoutExt(string path);
    static int FindFiles(string path, CArrayString *paths);
    static string LoadText(string path, int flags, CArrayString *lines);
    static bool SaveText(string text, string path, int flags, bool reset);
    static bool SaveText(CArrayString *lines, string path, int flags, bool reset);
};

// -----------------------------------------------------------------------------
// Проверить является ли путь существующим каталогом
// -----------------------------------------------------------------------------
static bool UFile::IsDirectory(string path) {
    ResetLastError();
    bool isFile = FileIsExist(path);
    return (_LastError == 5018);
}
...
 
Malik Arykov #:

У меня все оформлено через классы, которые лежат в *.mqh. Общие функции завернуты в классы, как статические методы. Классы разбиты по темам.

Например, кусок файла d:\Project\MQL5\Include\Cayman\UFile.mqh

хороший подход

 

вопрос к профи, все разбивают классы на отдельные файлы?

привык работать с с обычными функциями, в одном файле по направлениям

 

Дублирование объявления функции в С-стиле оправдано только для закрытия кода при публикации кода. Но редактировать аргументы нужно в ДВУХ местах! Зачем?

MQL проектируют Си-шники, поэтому они классы разбивают по привычке. Забавно, что при разбивки класса не разделяют его на файлы - бессмыслица. Но даже в С++ можно ВЕСЬ код класса запихать в .hpp (Java/C# стиль) и потерять на времени прекомпиляции - а этого в MQL нет изначально.

https://github.com/Roffild/RoffildLibrary/tree/master/Include/Roffild - Java/C# стиль

RoffildLibrary/Include/Roffild at master · Roffild/RoffildLibrary
RoffildLibrary/Include/Roffild at master · Roffild/RoffildLibrary
  • Roffild
  • github.com
Library for MQL5 (MetaTrader) with Python, Java, Apache Spark, AWS - RoffildLibrary/Include/Roffild at master · Roffild/RoffildLibrary
 

Java/C# стиль:

/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* https://github.com/Roffild/RoffildLibrary
*/
#include "ArrayListClass.mqh"

class CStatisticObject
{
public:
   ulong hash;
   int count;
   string describe;

   CStatisticObject(const ulong _hash, const string _describe = "none", const int _count = 0)
   {
      hash = _hash;
      describe = _describe;
      count = _count;
   }
};

/**
 * Counting data and printing out the accumulated information.
 */
class CStatistic
{
public:
   CArrayListClass<CStatisticObject> object;
   string name;

   CStatistic()
   {
      name = "NoName";
   }

   ~CStatistic()
   {
      print();
   }

   int index(const ulong hash)
   {
      const int count = object.size();
      for (int x = 0; x < count; x++) {
         if (object[x].hash == hash) {
            return x;
         }
      }
      return -1;
   }

   int plus(const ulong hash, const string describe = "none", const int number = 1)
   {
      const int ind = index(hash);
      if (ind > -1) {
         return object[ind].count += number;
      }
      if (object.add(new CStatisticObject(hash, describe))) {
         return object[object.size() - 1].count += number;
      }
      return 0;
   }

   int plus(CStatisticObject *value, const int number = 1)
   {
      const int ind = index(value.hash);
      if (ind > -1) {
         delete value;
         return object[ind].count += number;
      }
      if (object.add(value)) {
         return object[object.size() - 1].count += number;
      }
      delete value;
      return 0;
   }

   void print(const int file = INVALID_HANDLE)
   {
      if (file == INVALID_HANDLE) {
         if (MQLInfoInteger(MQL_OPTIMIZATION) == false) {
            Print("=== ", name, " -- Statistic ===");
            const int count = object.size();
            for (int x = 0; x < count; x++) {
               Print(object[x].describe, " = ", object[x].count);
            }
         }
      }
   }
};
 
Roffild #:

Дублирование объявления функции в С-стиле оправдано только для закрытия кода при публикации кода. Но редактировать аргументы нужно в ДВУХ местах! Зачем?

MQL проектируют Си-шники, поэтому они классы разбивают по привычке. Забавно, что при разбивки класса не разделяют его на файлы - бессмыслица. Но даже в С++ можно ВЕСЬ код класса запихать в .hpp (Java/C# стиль) и потерять на времени прекомпиляции - а этого в MQL нет изначально.

https://github.com/Roffild/RoffildLibrary/tree/master/Include/Roffild - Java/C# стиль

Разделение интерфейса и реализации удобно в первую очередь тем, что проектирование интерфейса и реализации можно вести в двух разных файлах, быстро переключаясь между интерфейсом и реализацией. Так же, при просмотре комитов в гите сразу видно, поменялся интерфейс или его реализация. Так же, что бы отдать интерфейс программисту без кода - приходится его вручную вырезать. Кроме этого, не ясно, для чего тода в принципе, даны mq5 файлы. Типа "главный файл в котором main"? 

 

Разделение класса в одном mqh - бессмысленное дублирование кода. И "интерфейсы" в текущей системе наследования - тоже бред полный. До идеи Java/C# не дотянули.

Разделение класса на mqh и mq5 - это вроде вообще не работает. Я пробовал разделить библиотеку сгенерированного кода на 1МБ для ускорения компиляции. Разделение библиотеки на закрытый код:

// lib.mq5
void getInputsForNetDump(double &inputs[]) export
{
   #include "../../Files/headers/InputsForNet_dump.mqh"
}

// lib.mqh
#import "lib.ex5"
void getInputsForNetDump(double &inputs[]);
#import

Эти же import/export не совместимы с классами! Или уже пофиксили?

Только mq5 превращается в ex5, а mqh нужен лишь для подсветки кода в редакторе. 
lib.mqh и lib.ex5 должны (в теории) продаваться через mql5.com без lib.mq5

Но можно подключить исходный код, если есть, без библиотеки ex5:
#include "lib.mq5"
void func()
{
   double inputs[100];
   getInputsForNetDump(inputs);
}

Причина обращения: