Создать массив своих объектов. Вернуть элемент класса функцией и поместить его в массив.

 

Добрый день! Помогите разобраться как правильно решить такую задачу: Создать объект пользовательского класса, вернуть его функцией и поместить в массив.

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
class CInfo
  {
public:
   string            symbol;
   ENUM_TIMEFRAMES   timeframe;
   MqlRates          rates[];

public:
   //--- Конструктор и деструктор
                     CInfo(void){};
                    ~CInfo(void){};

  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CInfo arInfo[1];
   arInfo[0]=returnInfo();
  }
//+------------------------------------------------------------------+
CInfo returnInfo()
  {
   CInfo i;
   i.symbol=_Symbol;

   return i;
  }
//+------------------------------------------------------------------+

ошибки:

'=' - structure have objects and cannot be copied    classTest.mq5    25    13
object of 'CInfo' cannot be returned, copy constructor 'CInfo::CInfo(const CInfo &)' not found    classTest.mq5    33    11

 

Можно примерно так:

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
class CInfo
  {
public:
   string            symbol;
   ENUM_TIMEFRAMES   timeframe;
   MqlRates          rates[];

public:
   //--- Конструктор и деструктор
                     CInfo(void){};
                    ~CInfo(void){ Print(symbol," ", EnumToString(timeframe)); };
                    

  };
  

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   CInfo *arInfo[1];
   arInfo[0] = returnInfo();
   
   if(CheckPointer(arInfo[0]))
   {
      delete arInfo[0];
   }
  }
//+------------------------------------------------------------------+
CInfo *returnInfo()
  {
   CInfo *i = new CInfo();
   i.symbol=_Symbol;

   return i;
  }
//+------------------------------------------------------------------+

Т.е. работать по указателю. Но обязательно не забывать удалять объекты (delete), созданные оператором new!

Документация: https://www.mql5.com/ru/docs/basis/types/object_pointers, https://www.mql5.com/ru/docs/basis/operators/newoperator, https://www.mql5.com/ru/docs/basis/operators/deleteoperator

Статья на тему: https://www.mql5.com/ru/articles/36

Документация по MQL5: Основы языка / Типы данных / Указатели объектов
Документация по MQL5: Основы языка / Типы данных / Указатели объектов
  • www.mql5.com
Основы языка / Типы данных / Указатели объектов - справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 
Андрей:

Добрый день! Помогите разобраться как правильно решить такую задачу: Создать объект пользовательского класса, вернуть его функцией и поместить в массив.

Ошибка в том, что вы создаете объект локально в функции ReturnInfo(), обычно считается что такие объекты уничтожаются при выходе из функции. Но вы перед уничтожением его возвращаете. Если бы это была простая переменная - никаких бы проблем не возникло, объект скопировался в вашу внешнюю переменную, а внутренний, тот, что был в функци - уничтожился бы.  У вас же объект содержит сложные структуры, которые при копировании также надо скопировать. О том вам и говорит первая ошибка - структура имеет объекты и не может быть просто скопирована.

Решение проблемы имеет два варианта - на первый вам прямо указала вторая ошибка, вам следует в описании объекта CInfo создать конструктор копирования с прототипом 'CInfo::CInfo(const CInfo &)' - и тогда ваш код заработает.

Второй вариант правильно указан Sergey Eremin - объект создается с помощью оператора new, и потом везде с ним работают через указатель. В этом случае, тоже правильно сказано - надо не забывать удалять объекты после того, как они вам перестанут быть нужны.

Лично мне больше нравится второй вариант, но начинающим бы я рекомендовал первый, как более простой.

 
Sergey Eremin:

Можно примерно так:

Т.е. работать по указателю. Но обязательно не забывать удалять объекты (delete), созданные оператором new!

Документация: https://www.mql5.com/ru/docs/basis/types/object_pointers, https://www.mql5.com/ru/docs/basis/operators/newoperator, https://www.mql5.com/ru/docs/basis/operators/deleteoperator

Статья на тему: https://www.mql5.com/ru/articles/36

Спасибо что помогаете! Извините за наглость, если не сложно покажите еще как вернуть такой массив указателей и встретить его в переменную для дальнейшего манипулирования.  

в данных попытках ошибки:

void OnStart()
  {
   CInfo *arInfo[];
   arInfo=ReturnArrayInfo();//Получить массив объектов CInfo

   //теперь можно все уничтожить
   for(int j=0;j<ArraySize(arInfo);j++)
     {
      if(CheckPointer(arInfo[j]))
        {
         Print("Уничтожение "+j);
         delete arInfo[j];
        }
     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CInfo[] *ReturnArrayInfo()
  {
   CInfo *arInfo[];

   for(int j=0;j<10;j++)
     {
      CInfo *i=returnInfo();
      if(CheckPointer(i)==POINTER_DYNAMIC)
        {
         ArrayResize(arInfo,ArraySize(arInfo)+1);
         arInfo[ArraySize(arInfo)-1]=i;
        }
     }
     
     return arInfo;
  }
//+------------------------------------------------------------------+
CInfo *returnInfo()
  {
   CInfo *i= new CInfo();
   i.symbol=_Symbol;

   return i;
  }
 
Андрей:

Спасибо что помогаете! Извините за наглость, если не сложно покажите еще как вернуть такой массив указателей и встретить его в переменную для дальнейшего манипулирования.  

в данных попытках ошибки:

Ммм, я бы сделал примерно так (но проверял в "полглаза", так что посмотрите сами, всё ли корректно работает):

class CInfo
  {
public:
   string            symbol;
   ENUM_TIMEFRAMES   timeframe;
   MqlRates          rates[];

public:
   //--- Конструктор и деструктор
                     CInfo(void){};
                    ~CInfo(void){ Print(symbol," ", EnumToString(timeframe)); };
                    

  };

void OnStart()
  {
   CInfo *arInfo[];
   ReturnArrayInfo(arInfo);//Получить массив объектов CInfo

   //теперь можно все уничтожить
   for(int j=0;j<ArraySize(arInfo);j++)
     {
      if(CheckPointer(arInfo[j]))
        {
         Print("Уничтожение "+j);
         delete arInfo[j];
        }
     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ReturnArrayInfo(CInfo *&arInfo[])
  {
   for(int j=0;j<10;j++)
     {
      CInfo *i=returnInfo();
      if(CheckPointer(i)==POINTER_DYNAMIC)
        {
         ArrayResize(arInfo,ArraySize(arInfo)+1);
         arInfo[ArraySize(arInfo)-1]=i;
        }
     }
  }
//+------------------------------------------------------------------+
CInfo *returnInfo()
  {
   CInfo *i= new CInfo();
   i.symbol=_Symbol;

   return i;
  }

Т.е. функция не возвращает массив, а ей передаётся массив указателей на объекты по ссылке (надеюсь верно выразился; если что, думаю меня поправят). А с этим массивом уже работаем в функции.

Документация (о передаче по ссылке): https://www.mql5.com/ru/docs/basis/types/this

P.S. не за что, лично мне всегда приятно помогать тем, кто пытается искать решения самостоятельно :)

Документация по MQL5: Основы языка / Типы данных / Ссылки. Модификатор & и ключевое слово this
Документация по MQL5: Основы языка / Типы данных / Ссылки. Модификатор & и ключевое слово this
  • www.mql5.com
Основы языка / Типы данных / Ссылки. Модификатор & и ключевое слово this - справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 
Андрей:
 

в данных попытках ошибки:

Насколько я понимаю, вы опять делаете ту же ошибку - сперва объявляете массив указателей на CInfo, потом заполняете его, а потом - возвращаете с одновременным уничтожением. При этом функция ReturnArrayInfo()
 у вас, насколько я вижу объявлена, как возвращающая указатель на массив, а в ее коде возвращается сам массив.

Вам следует почитать про создание объектов. В чем разница создания объекта, когда вы его просто объявляете в коде (создание объекта на стеке) и когда вы используете оператор new (создаете объект в "куче"). Обратить внимание на время жизни объекта, и порядку обращения к ним.

 
Андрей:

Спасибо что помогаете! Извините за наглость, если не сложно покажите еще как вернуть такой массив указателей и встретить его в переменную для дальнейшего манипулирования.  

в данных попытках ошибки:

Если работаете с объектами, то ВСЕГДА используйте стандартную библиотеку и контейнер CArraObj. Он для того и написан, что бы взять на себя работу по выделению памяти для объектов и их удаления "за кулисами". С ним в разы сокращается пользовательский код. Вот как с ним будет выглядеть Ваш алгоритм:

#include <Object.mqh>
#include <Arrays\ArrayObj.mqh>

class CInfo : public CObject
  {
public:
   string            symbol;
   ENUM_TIMEFRAMES   timeframe;
   MqlRates          rates[];

public:
   //--- Конструктор и деструктор
                     CInfo(void){};
                     CInfo(string symbol){this.symbol = symbol;}
                    ~CInfo(void){ Print(symbol," ", EnumToString(timeframe)); };
                    

  };

void OnStart()
  {
   CArrayObj ListInfo;
   // Добавляем десять элементов типа CInfo
   for(int i = 0; i < 10; i++)
      ListInfo.Add(new CInfo(Symbol());
   //Можно выйти и забить на ListInfo, все элементы в нем будут уничтожены автоматически!
  }
Т.е. получается, что никаких массивов указателей объявлять не нужно. Не нужно из переразмечать, инициализировать и удалять из них объекты. Все это уже давно сделано в классе CArrayObj. Нам осталось лишь многократно пользоваться его функционалом.
 
Vasiliy Sokolov:
+
 
Vasiliy Sokolov:

Если работаете с объектами, то ВСЕГДА используйте стандартную библиотеку и контейнер CArraObj. Он для того и написан, что бы взять на себя работу по выделению памяти для объектов и их удаления "за кулисами". С ним в разы сокращается пользовательский код. Вот как с ним будет выглядеть Ваш алгоритм:

Т.е. получается, что никаких массивов указателей объявлять не нужно. Не нужно из переразмечать, инициализировать и удалять из них объекты. Все это уже давно сделано в классе CArrayObj. Нам осталось лишь многократно пользоваться его функционалом.

Если делом всей жизни является написание одной единственной программы.

Если класс включает сотню методов и свойств, как кодить с таким подходом? Постоянно лазить в файл с классом и смотреть как там точно метод называется?

 
Dmitry Fedoseev:

Если делом всей жизни является написание одной единственной программы.

Как раз все наоборот. Это если вы пишете одну программу - можете не пользоваться всякими ООП-наворотами, весь советник написать в одном файле, и не писать ни одного комментария.

А вот если вы пишете много программ - то использование Стандартной Библиотеки - очень повышает эффективность написания кода и дальнейшую его поддержку.

Если класс включает сотню методов и свойств, как кодить с таким подходом? Постоянно лазить в файл с классом и смотреть как там точно метод называется?

Если класс имеет сотню методов и свойств - этот класс плохо продуман. Класс должен иметь только те методы и свойства, которые относятся непосредственно к нему самому, и если их больше десятка - это уже говорит о недостаточно хорошо продуманной структуре.

Ну а насчет "как упомнить названия методов" - дык именно так и делать, смотреть в .mqh-файл с заголовком класса. Все частые методы - быстро запоминаются. А за редкими - можно и заглянуть. (Считаю, что ни одно свойство не должно быть доступно извне, доступ к свойствам только через функции типа GetValue()).

 
George Merts:

Как раз все наоборот. Это если вы пишете одну программу - можете не пользоваться всякими ООП-наворотами, весь советник написать в одном файле, и не писать ни одного комментария.

А вот если вы пишете много программ - то использование Стандартной Библиотеки - очень повышает эффективность написания кода и дальнейшую его поддержку.

Если класс имеет сотню методов и свойств - этот класс плохо продуман. Класс должен иметь только те методы и свойства, которые относятся непосредственно к нему самому, и если их больше десятка - это уже говорит о недостаточно хорошо продуманной структуре.

Пункт X! Ну а насчет "как упомнить названия методов" - дык именно так и делать, смотреть в .mqh-файл с заголовком класса. Все частые методы - быстро запоминаются. А за редкими - можно и заглянуть. (Считаю, что ни одно свойство не должно быть доступно извне, доступ к свойствам только через функции типа GetValue()).

А расскажи мне про таблицу умножения, какая она правильная.

X. Вот и флаг вам в руки и барабан на шею. Вот это прогресс, вот это ООП! Нафиг бы тогда этот ООП вообще. Еще рассуждаете тут о том, какие классы правильные, какие нет. 

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