Вопросы по ООП в MQL5 - страница 83

 

Мдяя... Как с const у людей все запущено-то(((

Для понимания методов со спецификатором const

class CTest{
   int i;
public:
   CTest(int _i):i(_i){}
   int Get() const {return i;}
   int Get()   {return 2*i;}
};

void OnStart()
  {
   const CTest a(5);
   CTest b(8);
   Print(a.Get()); //5
   Print(b.Get()); //16
  }

А теперь сделайте

   //int Get() const {return i;}

, а потом наоборот:

//   int Get()   {return 2*i;}

)))

 
Alexandr Andreev:

Тоже вариантик все тот же код


Он же с констами

А ты уверен, что на вход

Compare(CObject const *node,int const mode=0)

всегда подашь

CChartObjectRectangleX*

, что бы без проверки писать

return (  Time(1)-dynamic_cast<const ME*>(node).Time(1));

?

 
Alexandr Andreev:

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

Так не годится. В Compare сигнатуру менять нельзя. Она в основном для того и нужна, чтобы работала штатная входящая в СБ сортировка методом QuickSort.

Поменяете сигнатуру, будет не переопределение вирт. функции, а перегрузка, и будет вызываться метод базового класса CObject, где return 0;

Ну конечно решается обертками (декорированием) к контейнерам, но зачем эти лишние движения, или тогда уж не применять СБ а всё с нуля писать.

 
Vladimir Simakov:

Вроде как один в один с твоим, только букв поменьше. Так-то дело вкуса, кому как больше нравится, но лишнюю переменную я убрал (скорее всего ее и компилятор бы убрал в рамках оптимизации).

По поводу моей проверки !node. По хорошему ее надо заменить на CheckPointer(node)==POINTER_INVALID, но это оверхед, вызов функции. Даже если заинлайнить, это все равно, как минимум, разыменование и проверка флага состояния. Если Compare методы только библиотека или конкретная, тобой написанная прога использовать будут, то лучше !node и по коду следить, что бы невалидный указатель не подать. Если лень за указателями следить или это библиотека для недоджунов, то тогда только CheckPointer(node)==POINTER_INVALID.

Если ты уберешь, выделенный тобой, спецификатор const, то ты не сможешь вызвать эти методы из константного объекта.

UPD: выделенную проверку можно убрать, так как она есть в вызываемых методах.

Владимир, вот как раз в данном случае CheckPointer  излишний же. dynamic_cast вернёт NULL при любом неудачном касте, в т.ч. если указатель битый. Если не прав, поправьте. Тестил давно, тест 5 секунд)

Механизм CheckPointer работы какой ( выражаюсь простыми словами, в низкоуровневых терминах не силён) - он смотрит  по указателю что за объект, динамический или статический, если получить информацию не удаётся, значит POINTER_INVALID. Это может быть в каком случае, если динамический объект удален, других ситуаций не знаю, ну или закастили мусор к указателю, но это компилятор должен проверять вроде,если лазейки не найти.

а dynamic_cast делает тоже самое, ещё и проверяя, можно ли привести этот указатель к требуемому типу, т.е. является ли он указателем этого типа, или дочернего класса.

Если указатель битый, то dynamic_cast не удастся определить ничего, и он возвращает NULL.

Именно поэтому я и не использовал CheckPointer. Хотя обычно везде эту проверку применяю от греха. Всё таки найти ошибку в ПО, которое не упало, чуть легче вроде бы)

А насчёт не-const - теоретически можно иметь метод типа GetRatingByAnyFormula() { m_rating01=Formula01(); return m_rating01;}

неудобно если его так сразу не использовать в сортировке, т.е. в любом случае сначала рейтинг считать, а потом сортировку по нему вызывать. Ну или как уже сказано писать свою СБ с нуля)

 
Aleksey Mavrin:

Так не годится. В Compare сигнатуру менять нельзя. Она в основном для того и нужна, чтобы работала штатная входящая в СБ сортировка методом QuickSort.

Поменяете сигнатуру, будет не переопределение вирт. функции, а перегрузка, и будет вызываться метод базового класса CObject, где return 0;

Ну конечно решается обертками (декорированием) к контейнерам, но зачем эти лишние движения, или тогда уж не применять СБ а всё с нуля писать.

Самый правильный способ все-ж на мкл не написать

 
Aleksey Mavrin:

Владимир, вот как раз в данном случае CheckPointer  излишний же. dynamic_cast вернёт NULL при любом неудачном касте, в т.ч. если указатель битый. Если не прав, поправьте. Тестил давно, тест 5 секунд)

Механизм CheckPointer работы какой ( выражаюсь простыми словами, в низкоуровневых терминах не силён) - он смотрит  по указателю что за объект, динамический или статический, если получить информацию не удаётся, значит POINTER_INVALID. Это может быть в каком случае, если динамический объект удален, других ситуаций не знаю, ну или закастили мусор к указателю, но это компилятор должен проверять вроде,если лазейки не найти.

а dynamic_cast делает тоже самое, ещё и проверяя, можно ли привести этот указатель к требуемому типу, т.е. является ли он указателем этого типа, или дочернего класса.

Если указатель битый, то dynamic_cast не удастся определить ничего, и он возвращает NULL.

Именно поэтому я и не использовал CheckPointer. Хотя обычно везде эту проверку применяю от греха. Всё таки найти ошибку в ПО, которое не упало, чуть легче вроде бы)

А насчёт не-const - теоретически можно иметь метод типа GetRatingByAnyFormula() { m_rating01=Formula01(); return m_rating01;}

неудобно если его так сразу не использовать в сортировке, т.е. в любом случае сначала рейтинг считать, а потом сортировку по нему вызывать. Ну или как уже сказано писать свою СБ с нуля)

  1. Compare-методы определены как public, значит любой недоджун, как ты ему в спецификации не тверди, обязательно туда невалидный дескриптор (давайте называть вещи своими именами) запихнет. Конечно, если это не библиотека, а так, для себя, то не нужно.
  2. Не знаю я как CheckPointer работает, там до ... вариантов может быть, но в любом случае - это такты процессора и обращение к памяти (легко может оказаться, что и к виртуальной).
  3. Насчет методов со спецификатором const. Если пишешь библиотеку, то всегда надо иметь ввиду, что объект может понадобиться константным, поэтому, в тех методах, которые не меняют состояние объекта, как бы желательно. Хотя, пока для себя, я и сам особо не заморачиваюсь с этим.
  4. Писать свою СБ, наверное это и есть правильное решение. Вот только интересных перспектив в соотношении оплата/трудозатраты не просматривается пока, а значит и не будет ничего доведенного, так, для собственных нужд только)
 
Vladimir Simakov:

По поводу моей проверки !node. По хорошему ее надо заменить на CheckPointer(node)==POINTER_INVALID, но это оверхед, вызов функции. 

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

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

 
Vladimir Simakov:
  1. Compare-методы определены как public, значит любой недоджун, как ты ему в спецификации не тверди, обязательно туда невалидный дескриптор (давайте называть вещи своими именами) запихнет. Конечно, если это не библиотека, а так, для себя, то не нужно.
  2. Не знаю я как CheckPointer работает, там до ... вариантов может быть, но в любом случае - это такты процессора и обращение к памяти (легко может оказаться, что и к виртуальной).
  3. Насчет методов со спецификатором const. Если пишешь библиотеку, то всегда надо иметь ввиду, что объект может понадобиться константным, поэтому, в тех методах, которые не меняют состояние объекта, как бы желательно. Хотя, пока для себя, я и сам особо не заморачиваюсь с этим.
  4. Писать свою СБ, наверное это и есть правильное решение. Вот только интересных перспектив в соотношении оплата/трудозатраты не просматривается пока, а значит и не будет ничего доведенного, так, для собственных нужд только)

1. Не спорю, но я то говорил о том что НЕ ТРЕБУЕТСЯ  CheckPointer (даже для недоджунов) , т.к.  dynamic_cast НЕ может вернуть какой-то НЕвалидный указатель, только NULL.

2. Даже интересно, но не могу сходу придумать пример, как можно получить невалидный указатель, кроме того как убить динамический объект, ну или в процессе работы напрямую память "запачкать".

Полагаю такие способы ещё есть, но все они скорее всего лежат в плоскости обхода проверок компилятора.

3,4 Согласен

P.S.

Видимо я заблуждался насчёт 1-го. Тест говорит об обратном. Значит показалось)

void OnStart()
  {
      CChartObjectRectangle *base = new CChartObjectRectangle();
      CChartObjectRectangleX *rect = new CChartObjectRectangleX();
       CChartObjectRectangle * dbase  ;
      const CChartObjectRectangleX *drect  ;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL, " check? ",!dbase," broken? ", EnumToString( CheckPointer(dbase) ));
      delete base;
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));
      dbase=dynamic_cast< CChartObjectRectangle *>  (base);   
      Print("dbase= ",dbase, " NULL ? ",dbase==NULL," check? ",!dbase, " broken? ", EnumToString( CheckPointer(dbase) ));   
  }
 
можно ли статический массив объявить в секции класса public, а инициализировать в конструкторе? (как указано ниже) (или только поэлементно?)
 bool Mass[5] = { false, true, false, true, true };
 
Pavel Verveyko:
можно ли статический массив объявить в секции класса public, а инициализировать в конструкторе? (как указано ниже) (или только поэлементно?)

Можно инициализировать локальный массив и выполнить ArrayCopy в соответствующее массив-поле:

class A{
public:
   bool Mass[5];
   A(){
       bool mass_init[5] = { false, true, false, true, true };
       ArrayCopy(Mass, mass_init);
   }
};
Причина обращения: