Проект советника - страница 5

 

George Merts
Стандартный CObject - это "объект списка или сортированного массива". CMyObject - это CObject, имеющий определенный тип, и содержащий некоторое значение, данное при его создании. Этот объект мне понадобился всвязи с повсеместным приведением объектов к базовому абстрактному классу - чтобы понимать по указателю, на какой именно объект "на самом деле" указывает. Тип CMyObject - устанавливается как раз той самой функцией SetMyObjectType(). Эта функция в обязательном порядке вызывается в конструкторах любых наследников от CMyObject, чтобы назначить идентификатор класса, к которому принадлежит создаваемый объект.

У Вас конструктор открытый и непараметризованный:

class CTradeHistoryI: public CMyObject
{
public:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

Это значит, что наследник может установить свой тип, а может и не установить. Т.е. если внутри наследника забудете вызвать метод SetMyObjectType - пиши пропало.

Что можно сделать?

1. Закрыть конструктор от создания из вне:

class CTradeHistoryI: public CMyObject
{
protected:
   void CTradeHistoryI() {    SetMyObjectType(MOT_TRADE_HISTORY_I); };
}

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

2. Зададим требование явной типизации в момент создания экземпляра:

enum ENUM_OBJ_TYPE
{
   OBJ_HIST_DEALS_LIST,
   OBJ_HIST_ORDERS_LIST
   ...
};

class CTradeHistoryI: public CMyObject
{
private:
   ENUM_OBJ_TYPE   m_obj_type;
protected:
   CTradeHistoryI(ENUM_OBJ_TYPE obj_type)
   {
      m_obj_type = obj_type;
   }
public:
   ENUM_OBJ_TYPE ObjectType(void) const
   {
      return m_obj_type;
   }
};

class CTradeHistory : public CTradeHistoryI
{
public:
   CTradeHistory(void);
};

CTradeHistory::CTradeHistory(void) : CTradeHistory(OBJ_HIST_DEALS_LIST)
{
}

Все, теперь ни один потомок не сможет создать себя без явного задания типа.

 
Vasiliy Sokolov:

Зачем изобретать велосипед в виде CMyObject, когда есть стандартный и всем понятный CObject?

Уж не знаю, что хорошего вы нашли в MQL-овском CObject.  Два ненужных указателя, запихиваемых в каждый объект = 16 потерянных байт + лишний оверхед при выделении памяти и инциализации этих указателей.  ООП сам по себе замедляет производительность, а если ещё и такие бестолковые решения...
 
Alexey Navoykov:
Уж не знаю, что хорошего вы нашли в MQL-овском CObject.  Два ненужных указателя, запихиваемых в каждый объект = 16 потерянных байт + лишний оверхед при выделении памяти и инциализации этих указателей.  ООП сам по себе замедляет производительность, а если ещё и такие бестолковые решения...

Выучите ООП для начала, потом обсудим. Инициализация m_prev, m_next в общем случае не происходит если что.

 
Vasiliy Sokolov:

Выучите ООП для начала, потом обсудим. Инициализация m_prev, m_next в общем случае не происходит если что.

Только после вас.

И так для сведений, инициализация указателей в MQL производится всегда.

 
Vasiliy Sokolov:

У Вас конструктор открытый и непараметризованный:

Это значит, что наследник может установить свой тип, а может и не установить. Т.е. если внутри наследника забудете вызвать метод SetMyObjectType - пиши пропало.

Что можно сделать?

...

Да, действительно, я в некоторых случаях забываю указать SetMyObjectType() - и объекты создаются с типом CMyObject по умолчанию. 

И метод решения - хороший. 

Предложения принимаются.

Хотя, протектед-конструктор мне не нравится.

 
George Merts:

Да, действительно, я в некоторых случаях забываю указать SetMyObjectType() - и объекты создаются с типом CMyObject по умолчанию. 

И метод решения - хороший. 

Предложения принимаются.

Хотя, протектед-конструктор мне не нравится.

Протектед-конструктор усложняет жизнь только тем классам, которые непосредственно наследуются от родителя с таким конструктором. Но вот на пользовательском уровне, создавать производные объекты можно не задумываясь и свободно.

Поэтому неудобство наблюдаться не должно. 

Ну и других вариантов в MQL нет, т.к. нет системы контроля типов, вернее она есть, но в недоразвитом виде, вот и приходится защищать тип через скрытие конструктора. 

 
Alexey Navoykov:
Уж не знаю, что хорошего вы нашли в MQL-овском CObject.  Два ненужных указателя, запихиваемых в каждый объект = 16 потерянных байт + лишний оверхед при выделении памяти и инциализации этих указателей.  ООП сам по себе замедляет производительность, а если ещё и такие бестолковые решения...

Да почему "бестолковые" ? Оверхед - по-моему, очень небольшой, и он явно стоит удобства, которые дает CObject при организации списков и сортированных массивов.

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

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

Так что "ненужный оверхед" может теряться совсем не там, где мы его ищем.

 
George Merts:

Так что "ненужный оверхед" может теряться совсем не там, где мы его ищем. 

Да не спорьте Вы с ним. Его единственная цель похоливарить. Ничего таким как он никогда не докажите. Лучшая стратегия общения с подобными персонажами - это полный игнор.
 
George Merts:

Да почему "бестолковые" ? Оверхед - по-моему, очень небольшой, и он явно стоит удобства, которые дает CObject при организации списков и сортированных массивов.

Эти "удобства" реализованы через одно место. Что это за список такой, который что-то меняет в твоих объектах?  По сути получается что константные объекты нельзя поместить в список.  Или вот представь ситуацию, что твой объект, находящийся в таком списке, ты отправляешь в некую функцию, которая тоже помещает его в свой список, и потом получаешь обратно свой объект с изменённым prev и next, и пошло поехало...

В цивилизованном мире списки реализуются через вспомогательные объекты Node, хранящие требуемые указатели.  А трогать сами объекты пользователя - это нонсенс. Так что дело не только в оверхеде, а в принципиальной неправильности всего этого.  Разработчики что-то слепили на скорую руку, а вы и рады, будто так и должно быть.

 
Alexey Navoykov:

Эти "удобства" реализованы через одно место. Что это за список такой, который что-то меняет в твоих объектах?  По сути получается что константные объекты нельзя поместить в список.  Или вот представь ситуацию, что твой объект, находящийся в таком списке, ты отправляешь в некую функцию, которая тоже помещает его в свой список, и потом получаешь обратно свой объект с изменённым prev и next, и пошло поехало...

В цивилизованном мире списки реализуются через вспомогательные объекты Node, хранящие требуемые указатели.  А трогать сами объекты пользователя - это нонсенс. Так что дело не только в оверхеде, а в принципиальной неправильности всего этого.  Разработчики что-то слепили на скорую руку, а вы и рады, будто так и должно быть.

Ну, да, константные объекты в список не запишешь.

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

"Как надо делать"  - это каждый горазд орать. А вот предложить что-то - и ВНЕЗАПНО оказывается нечего. 

Даже те участники,  кто реально предлагают различные программные решения - не предлагают замены CObject'y - чаще вобще его не используют, реже используют его функциональность, не обращая внимания на "реализацию через одно место".  А значит - реализация вполне себе годная.

Была бы плохая - давно бы уже предложили замену.