как передать массив в класс - страница 3

 
fxsaber:

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

То есть передать в функцию переменное количество массивов? Такой код будет невозможно отлажить.

 
Georgiy Merts:

Да ну ???

Попробуй возможность не копировать массив, а передавать адрес - дорого стоит. 

И в чем проблема передать массив по ссылке в функцию?

 

Georgiy Merts:

В частности, я уже не раз показывал, как у меня организован доступ к истории или к позиции - ты получаешь виртуальный интерфейс, в котором одни функции. Внутренняя реализация - полностью скрыта. Именно инкапсуляция ООП это и позволяет. Без ООП такую инкапсуляцию сделать не выйдет.

Такой код будет нечитаемым и баги в нем замучаешься ловить. Причем создается проблема на ровном месте, так как логически он ничего не делает.

 
Andrei:

И в чем проблема передать массив по ссылке в функцию?

Это когда тебе надо в одну функцию передать один массив.

А вот когда у тебя вложенность превышает десяток, в каждой функции из этих "матрешек" требуются какие-то данные, а массивы не нужны, а массивы понадобятся на самом "глубоком" уровне - то тебе придется передавать массивы по ссылкам внутрь всех этих функция-"матрешек", И тащить все это будет весьма напряжно.

С классом же - ты получаешь указатель, сохраняешь его внутри класса, и лишь на самом глубоком уровне - обращаешься к массиву, используя указатель.

 
Georgiy Merts:

С классом же - ты получаешь указатель, сохраняешь его внутри класса, и лишь на самом глубоком уровне - обращаешься к массиву, используя указатель.

С указателями давно уже никто не работает со времен С, это плохой стиль ибо код будет невозможно отлаживать.

 
Andrei:

Такой код будет нечитаемым и баги в нем замучаешься ловить. Причем создается проблема на ровном месте, так как логически он ничего не делает.

Он будет никак не менее читаемым, чем код в "функциональном" стиле с массой ifdef'ов. 

Никакой проблемы не создается - написать-то можно и так, и так. Но вот когда потребуется отладка, или, особенно, модификация - ООП-подход дает очень существенные плюсы.

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

 

Georgiy Merts:

Если ты-монстр запоминания - то вобще, можно все данные свалить в один огромный глобально доступный массив

Как раз чтобы помнить все интерфейсы где они что скрывают, куда ведут и зачем и надо быть монстром.)

 
Andrei:

С указателями давно уже никто не работает со времен С, это плохой стиль ибо код будет невозможно отлаживать.

Всегда работаю ТОЛЬКО с указателями. Код прекрасно отлаживается.

Интересно, как ты собираешься работать без указателей, если оператор new возвращает именно указатель ?

Плохой ли это стиль ? Ну не знаю... Я не раз уже показывал свои функции...

Допустим, вот функция класса CDataProviderT (провайдер данных), которая создает указанную таймсерию по ее типу, символу, таймфрейму, с нужным размером:

CSeriesI* CDataProviderT::_CreateSeries(EAllSeries asSeriesType,ECurrencySymbol csSymbol,ENUM_TIMEFRAMES etTimeframe,uint uiSize)
{
   CTimeSeriesT* ptscResult = NULL;

   switch(asSeriesType)
      {
      case AS_OPEN:
         ptscResult = new CTSOpen;
         break;

      case AS_HIGH:
         ptscResult = new CTSHigh;
         break;

      case AS_LOW:
         ptscResult = new CTSLow;
         break;

      case AS_CLOSE:
         ptscResult = new CTSClose;
         break;

      case AS_SPREAD:
         ptscResult = new CTSSpread(GetConstSpread(csSymbol));
         break;

      case AS_TIME:
         ptscResult = new CTSTime;
         break;

      case AS_TICK_VOLUME:
         ptscResult = new CTSVolume(true);
         break;

      case AS_REAL_VOLUME:
         ptscResult = new CTSVolume(false);
         break;

      default:
         ASSERT(false);
         return(NULL);
      };   

   if(ptscResult == NULL)
      {      
      ASSERT_DSC(false,"Не удалось создать таймсерию");
      return(NULL);
      };
      
   if(ptscResult.Init(csSymbol,etTimeframe,uiSize)==false)
      {      
      ASSERT_DSC(false,"Не удалось инициализировать таймсерию");
      delete ptscResult;
      return(NULL);
      };

   if(m_aoTimeSeries.Add(ptscResult) == false)
      {      
      ASSERT_DSC(false,"Не удалось присоединить таймсерию к списку");
      delete ptscResult;
      return(NULL);
      };

   return(ptscResult);      
};

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

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

Как подобное сделать без указателей ?

Да и отладка этого кода - не такая уж мудреная...

 
Andrei:

Как раз чтобы помнить все интерфейсы где они что скрывают, куда ведут и зачем и надо быть монстром.)

Интересно-интересно.

Я уже не раз показывал, вот интерфейс торговой позиции:

class CTradePositionI: public CMyObject
{
public:
   // Выбор существующей позиции. 
   // Указывается магик и символ, по которому выбираются действующие ордера.
   // Если ulMagic = 0 - выбираются все позиции по всем магикам.
   // Если ECurrencySymbol = CS_UNKNOWN - выбираются все позиции по всем символам
   // Если ECurrencySymbol = CS_CURRENT - запрашивается функция Symbol(), и выбираются все позиции по этому символу
   // Возвращает число компонент позиции внутри позиции (может быть нулевым если позиции нет) или WRONG_VALUE в случае ошибок
   // Каждая фабрика (наследник CEAPartsFactoryT) имеет одну позицию, которая на каждом CEAPartsFactoryT::OnRefresh()
   // обновляется в соответствии с магиком и рабочим символом фабрики. 
   virtual int Select(ulong ulMagic = 0,ECurrencySymbol csSymbol = CS_CURRENT) = 0;

   virtual uint GetTotalComponents() const = 0;  // Получение общего числа компонент
   virtual CTradePosComponentI* GetComponent(uint uiComponentIdx) const = 0;
   
};

Вызываем Select(), а потом можем запросить общее число компонент, и каждую компоненту в отдельности.

ЧТО в данном интерфейсе - тебе надо "запоминать" ?  Ты физически не можешь сделать ничего другого, кроме как выбрать позицию, и перебрать открытые ее компоненты. В функции - ты тоже сунуться не можешь, они приравнены нулю, чисто виртуальны. Но в отладчике - это возможно.

А по-твоему, ты должен здесь что-то запомнить, чтобы не перепутать ? Что ?