Предположим? Начните с того каком месте у Вас возникают проблемы от того, что идентификатор типа объектов целочисленный?
Если не возникают, тогда какого ... бодягу разводить?
Ежели каждый ламер начнет свои порядки устанавливать в стандартной библиотеке, тогда получится раздрай.
Коли Вам не нравится стандартная, то переписывайте свою нестандартную, как больше нравится и будет вам счастье.
А давайте в этой теме обсудим стандартную библиотеку - все-таки с нее обычно начинают все, обсудим здесь чего бы хотелось видеть в стандартной библиотеке, разработаем более приличную логику. Коллективным разумом так сказать. Здесь же обсудим непонятки, которые возникают при изучении кода стандартной библиотеки.
Мне очень нравится идеология Стандартной Библиотеки, и очень жаль, что на МТ4 она еще сильно недоделана, а кроме того, существенно иначе работают некоторые классы таймсерий.
Как затеявший тему начну. С истоков :) . CObject
Итак при рассмотрении CObject видим не описанный тут, на сайте
Очень нужная штука, скажу я вам, особенно, когда юзаешь свои унаследованные классы совместно со стандартными и хочется определить, что же у меня тут такое. Однако непонятки - и вопрос разработчикам - ну почему int??? Не кажется ли что string было бы ловчее??? Ну посудите сами - разные разработчики с гораздо большей вероятностью присвоят один и тот же int для объектов, нежели string, имя собственное???
int - на мой взгляд, гораздо лучше, чем string, поскольку позволяет использовать его в операторе switch(). Кроме того, int позволяет проводить хитрые преобразования, скажем, простым прибавлением константы и генерацией нового объекта полученного типа (хотя, последний пример, мне кажется, весьма надуманным, да и вобще опасным для использования).
string - хорош только для контроля объектов самим человеком во время отладки.
А давайте в этой теме обсудим стандартную библиотеку - все-таки с нее обычно начинают все, обсудим здесь чего бы хотелось видеть в стандартной библиотеке, разработаем более приличную логику. Коллективным разумом так сказать. Здесь же обсудим непонятки, которые возникают при изучении кода стандартной библиотеки.
Как затеявший тему начну. С истоков :) . CObject
Итак при рассмотрении CObject видим не описанный тут, на сайте
Очень нужная штука, скажу я вам, особенно, когда юзаешь свои унаследованные классы совместно со стандартными и хочется определить, что же у меня тут такое. Однако непонятки - и вопрос разработчикам - ну почему int??? Не кажется ли что string было бы ловчее??? Ну посудите сами - разные разработчики с гораздо большей вероятностью присвоят один и тот же int для объектов, нежели string, имя собственное???
Топикстартер, сам не осознавая, затронул довольно насущную проблему динамической идентификации типов в MQL5.
Сама стандартная библиотека - профессиональный и продуманный программный код высочайшего качества. Ее архитектор поистине профессионал программирования. Это чувствуется буквально в каждой строке кода. Я плотно работаю с стандартной библиотекой и не раз и не два погружался в ее логику. Любое желание что-то изменить в ней должно подвергаться сильному сомнению. Однако действительно есть несколько "но".
Первое и основное "Но" это идентификация типа. Топикстарет правильно заметил что string в качестве основополагающего типа был бы более предпочтителен, но не правильно понял почему.
Дело в том, что во-времена написания CObject еще не было шаблонов и int как тип был наиболее правильным решением, потому что как минимум прозрачно позволял использовать строго типизированный enum в качестве идентификатора типа. Любой потомок CObject переопределявший Type() и возвращавший вместо int свой enum гарантировал свою уникальность. Поясню на примере:
#include <Object.mqh> #include <Arrays\ArrayObj.mqh> /// /// Каждый класс проекта переопределяет /// enum ENUM_TYPE_CLASS { /// /// Идентификатор класса A /// CLASS_A, /// /// Идентификатор класса B /// CLASS_B }; class BaseClass : public CObject { public: /// /// Возвращает тип класса. /// virtual int Type() { return type; } /// /// Выводит тип класса в терминал. /// void PrintType() { printf(EnumToString(type)); } protected: /// /// Гарантируем создание экземпляра с определенным типом. /// BaseClass(ENUM_TYPE_CLASS mType){ type = mType;} /// /// Содержит защищенный идентификатор класса. /// ENUM_TYPE_CLASS type; }; /// /// Класс A. /// class ClassA : public BaseClass { public: ClassA() : BaseClass(CLASS_A){;} }; /// /// Класс B. /// class ClassB : public BaseClass { public: ClassB() : BaseClass(CLASS_B){;} }; void OnStart() { //Создадим десять случайных классов и запишем их в массив: CArrayObj objects; int i = 0; do { CObject* obj = NULL; switch(rand()%2) { case 0: obj = new ClassA(); break; default: obj = new ClassB(); } objects.Add(obj); }while(i++<9); i = 0; do { BaseClass* baseClass = objects.At(i); baseClass.PrintType(); }while(i++<objects.Total()-1); }
Т.е. если все классы в проекте будут наследоваться от BaseClass c защищенным конструктором, то получить неправильный идентификатор не получиться. Однако по-прежнему есть необходимость в использовании дополнительной прослойки BaseClass. Потому что в противном случае приведение Type к ENUM_TYPE_CLASS не гарантируется. Использование же int как есть не представляется возможным, потому что этот тип не строго типизирован и может принимать потенциально любые значения.
В целом, если полагаться на дисциплину программиста такой способ вполне приемлем, однако с ведением шаблонов теоретически можно повысить типобезопасность объектов и для этого Type действительно надо перевести на string. Дело в том, что в шаблонах есть замечательный оператор typename и значит возможно динамическая идентификация по имени самого класса:
//+------------------------------------------------------------------+ //| Возвращает в строковом виде тип | //+------------------------------------------------------------------+ template<typename T> string GetTypeName(const T &t) { //--- вернем тип в виде строки return(typename(T)); //--- }
С этой функцией не имеет значение принадлежит класс к CObject или нет. Эта функция вернет гарантированный и уникальный идентификатор класса пусть и в виде строки. Думаю по схожим причинам в .NET и в C# - вершине всех языков программирования, в основе рефлексии и динамической идентификации лежит именно string а не другой тип данных.
Однако с typename связан неприятный момент. Функция возвращает не фактический тип класса, а тот тип, который был ей передан. Т.е. если создать производный класс и присвоить его объект указателю базового класса, то typename вернет имя базового класса, в то время как на самом деле ей будет передан объект производного класса. Поэтому для того, что бы изменить идентификацию типов в лучшую сторону необходимо изменить не только CObject а еще typename, что бы он возвращал фактический тип объекта, не зависимо от текущего типа указателя на него. Во-вторых, должна быть конструкция позволяющая получать доступ к типу родительского класса лежащего о основе производного класса. Это поднимет безопасность и прозрачность динамической идентификации типов на порядок! Это позволит писать например такую штуку:
do { BaseClass* baseClass = objects.At(i); if(baseClass.TypeIs(CassA)) printf("This class A"); if(baseClass.TypeIs(CassB)) printf("This class B"); if(baseClass.TypeIs(BaseClass)) printf("This Base Class"); }while(i++<objects.Total()-1);
Омг...
Стандартная функция typeof порешает все проблемы. И это единственный нормальный способ.
М-да, забиди ногами, обозвали ламером.... Вот только мой опыт программирования уже приближается к 20 годам. Злые вы, уйду я от вас...
М-да, забиди ногами, обозвали ламером.... Вот только мой опыт программирования уже приближается к 20 годам. Злые вы, уйду я от вас...
Что-то не похоже.
А как же отстаивание своего мнения ? Давай аргументы, почему string лучше ?
По мне - так enum типов объектов - это самое правильное решение, и лично я давно уже сделал CMyObject, в котором объявлено перечисление EMyObjectTypes, внутренняя переменная этого перечисления, которая присваивается в конструкторе, и функция EMyObjectTypes GetType(); там, где невозожно использование механизма виртуальных функций - использую switch(), а со строкой пришлось бы использовать операторы сравнения строк, работающие значительно медленнее.
Что-то не похоже.
А как же отстаивание своего мнения ? Давай аргументы, почему string лучше ?
По мне - так enum типов объектов - это самое правильное решение, и лично я давно уже сделал CMyObject, в котором объявлено перечисление EMyObjectTypes, внутренняя переменная этого перечисления, которая присваивается в конструкторе, и функция EMyObjectTypes GetType(); там, где невозожно использование механизма виртуальных функций - использую switch(), а со строкой пришлось бы использовать операторы сравнения строк, работающие значительно медленнее.
Непохоже потому что диалекты Си я очень поверхностно юзаю последние 15 лет. Сначала это была специализированная банковская система, потом 1С. Так, что, да, кое в чем я новичок. Но не в технологиях.
Насчет перечислений... Не, ну, блин вы даете - я что-то не понял - коли у вас возникает новый тип объекта - в лезете в это перечисление и добавляете туда новый тип??? Несерьезно мягко говоря.
Насчет int и строки. Имеется в виду, что разные разработчики могут писать свои классы, например, унаследованные от ExpertSignal, вы, подключая их к своему эксперту и добавляя их с массив фильтров, можете работать с ними по разному. int для этого тоже подходит, конечно, но, как я уже писал с очень большой вероятностью разные разработчики присвоят один и тот же код (например 666) - типа вот так, оригинально... Точно также я считаю некорректным использование целочисленного magic. Все хорошо, пока юзер не запустит два эксперта на одном символе с одинаковым маджиком...
И по хорошему метод Type делать статическим, да вот виртуальные со статическими не совместимы, а значит нельзя гарантировать их наследство....
Я вообще-то не с этой целью ветку начинал.
Стандартная библиотека хороша для изучения основ mql, работы с таймсериями и специализированными функциями. Но ведь в ней и много недостатков, а? Так давайте сообща делать предложения о доработке, можно ведь ее (библиотеку) значительно расширить...
Насчет свитч и сравнения строк, которые медленнее... А это ничего, что в стандартной библиотеке метод Direction вызывается для каждого из фильтров по нескольку раз на каждом тике??? А ведь это самый тяжелый метод, где зачастую рассчитываются дивергенции осциляторов...
Ладно, пусть каждый свою нетленку изобретает...
Насчет перечислений... Не, ну, блин вы даете - я что-то не понял - коли у вас возникает новый тип объекта - в лезете в это перечисление и добавляете туда новый тип??? Несерьезно мягко говоря.
Предложи свой вариант.
И если будет string - чем оно лучше ? Опять же - добавляется новый тип, надо его назвать в конструкторе.
Я просто наследую от CMyObject'а далеко не все свои объекты. Исходя из принципов Стандартой Библиотеки CObject - это "объект множества", а не любой объект. В нем есть функции передвижения по списку, сравнения и зарузки-сохранения. Разумно использовать наследников от CObject'а именно тогда, когда требуется множество объектов.
с очень большой вероятностью разные разработчики присвоят один и тот же код (например 666) - типа вот так, оригинально...
На мой взгляд, в одном проекте такое пересечение все же маловерятно. Но, тем не менее, опасность, конечно, есть. А со строкой - такой опасности меньше ?
Стандартная библиотека хороша для изучения основ mql, работы с таймсериями и специализированными функциями. Но ведь в ней и много недостатков, а? Так давайте сообща делать предложения о доработке, можно ведь ее (библиотеку) значительно расширить...
Никаких проблем, только поддерживаю. Лично мне СБ в МТ5 очень даже нравится, и я надеюсь, что она будет по-максимуму перенесена на МТ4, торговыми классами и классами экспертов (чего сейчас пока нет). Кроме этого момента - я особо недостатков не вижу. Мне, скажем, крайне не нравится, что я не могу хранить указатель или ссылку на массив, но это, скорее претензия не к СБ, а к самому MQL
#include <Object.mqh> #include <Arrays\ArrayObj.mqh> class BaseClass : public CObject { public: /// /// Возвращает тип класса. /// virtual string Type1() { return type; } /// /// Выводит тип класса в терминал. /// void PrintType() { printf(type); } protected: /// /// Гарантируем создание экземпляра с определенным типом. /// template<typename T> BaseClass( T &mType){ type = typename(T);} /// /// Содержит защищенный идентификатор класса. /// string type; }; /// /// Класс A. /// class ClassA : public BaseClass { public: ClassA() : BaseClass(this){;} }; /// /// Класс B. /// class ClassB : public BaseClass { public: ClassB() : BaseClass(this){;} }; void OnStart() { //Создадим десять случайных классов и запишем их в массив: CArrayObj objects; int i = 0; do { CObject* obj = NULL; switch(rand()%2) { case 0: obj = new ClassA(); break; default: obj = new ClassB(); } objects.Add(obj); }while(i++<9); i = 0; do { BaseClass* baseClass = objects.At(i); if(baseClass.Type1()=="ClassA") printf("This class A"); if(baseClass.Type1()=="ClassB") printf("This class B"); if(baseClass.Type1()=="BaseClass") printf("This Base Class"); }while(i++<objects.Total()-1); }
Топикстартер, сам не осознавая, затронул довольно насущную проблему динамической идентификации типов в MQL5.
Сама стандартная библиотека - профессиональный и продуманный программный код высочайшего качества. Ее архитектор поистине профессионал программирования. Это чувствуется буквально в каждой строке кода. Я плотно работаю с стандартной библиотекой и не раз и не два погружался в ее логику. Любое желание что-то изменить в ней должно подвергаться сильному сомнению. Однако действительно есть несколько "но".
Первое и основное "Но" это идентификация типа. Топикстарет правильно заметил что string в качестве основополагающего типа был бы более предпочтителен, но не правильно понял почему.
Дело в том, что во-времена написания CObject еще не было шаблонов и int как тип был наиболее правильным решением, потому что как минимум прозрачно позволял использовать строго типизированный enum в качестве идентификатора типа. Любой потомок CObject переопределявший Type() и возвращавший вместо int свой enum гарантировал свою уникальность. Поясню на примере:
Т.е. если все классы в проекте будут наследоваться от BaseClass c защищенным конструктором, то получить неправильный идентификатор не получиться. Однако по-прежнему есть необходимость в использовании дополнительной прослойки BaseClass. Потому что в противном случае приведение Type к ENUM_TYPE_CLASS не гарантируется. Использование же int как есть не представляется возможным, потому что этот тип не строго типизирован и может принимать потенциально любые значения.
В целом, если полагаться на дисциплину программиста такой способ вполне приемлем, однако с ведением шаблонов теоретически можно повысить типобезопасность объектов и для этого Type действительно надо перевести на string. Дело в том, что в шаблонах есть замечательный оператор typename и значит возможно динамическая идентификация по имени самого класса:
С этой функцией не имеет значение принадлежит класс к CObject или нет. Эта функция вернет гарантированный и уникальный идентификатор класса пусть и в виде строки. Думаю по схожим причинам в .NET и в C# - вершине всех языков программирования, в основе рефлексии и динамической идентификации лежит именно string а не другой тип данных.
Однако с typename связан неприятный момент. Функция возвращает не фактический тип класса, а тот тип, который был ей передан. Т.е. если создать производный класс и присвоить его объект указателю базового класса, то typename вернет имя базового класса, в то время как на самом деле ей будет передан объект производного класса. Поэтому для того, что бы изменить идентификацию типов в лучшую сторону необходимо изменить не только CObject а еще typename, что бы он возвращал фактический тип объекта, не зависимо от текущего типа указателя на него. Во-вторых, должна быть конструкция позволяющая получать доступ к типу родительского класса лежащего о основе производного класса. Это поднимет безопасность и прозрачность динамической идентификации типов на порядок! Это позволит писать например такую штуку:
Спасибо, насчет "сам не сознавая", позабавило :)
На самом деле именно это я и имел ввиду, однако было лениво столько писать.
Сейчас, когда я могу скопипастить ваш пример, и немного его подкорректировать я поясню. Да, именно шаблоны и они работают, как надо.
Только, походу, я неверно интерпретировал сущность метода Type, он, как оказалось, несколько для иного, действительно int и enum тут как раз.
Чтож, предлагаю ввести метод TypeObject, начиная с CExpertBase я думаю.

- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
А давайте в этой теме обсудим стандартную библиотеку - все-таки с нее обычно начинают все, обсудим здесь чего бы хотелось видеть в стандартной библиотеке, разработаем более приличную логику. Коллективным разумом так сказать. Здесь же обсудим непонятки, которые возникают при изучении кода стандартной библиотеки.
Как затеявший тему начну. С истоков :) . CObject
Итак при рассмотрении CObject видим не описанный тут, на сайте
Очень нужная штука, скажу я вам, особенно, когда юзаешь свои унаследованные классы совместно со стандартными и хочется определить, что же у меня тут такое. Однако непонятки - и вопрос разработчикам - ну почему int??? Не кажется ли что string было бы ловчее??? Ну посудите сами - разные разработчики с гораздо большей вероятностью присвоят один и тот же int для объектов, нежели string, имя собственное???