Russian Qt Forum
Апрель 29, 2024, 09:14 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4 5 6   Вниз
  Печать  
Автор Тема: Как узнать о типе, до выполнения dynamic_cast?  (Прочитано 32878 раз)
Eten
Гость
« Ответ #30 : Март 07, 2011, 15:41 »

brankovic, спасибо, но я уже это понял, когда вы намекнули про утечку (этот момент я тоже исправил), поэтому там, где у себя лишним поставил деструктор для dt, его же и убрал. Работу с указателями привел потому, что вы спрашивали. А работа с указателем, которая была в них приведена, используется для получения NNumeric из тех мест, где он хранится в виде указателя на базовый класс. Если кто-то знает, как можно работать с производными и базовыми классами без указателей вообще, мне очень интересно посмотреть и узнать как это делается, т.к. Страустрап в своей книге все делал с помощью указателей.  Подмигивающий

Цитата: Igors
Здесь позвольте с Вами не согласиться. Как человек пишет - так и думает.
Я с вами полностью согласен, но по своему опыту знаю, что отношусь к тем людям, у которых понимание опережает формулирование мыслей. Из-за этого иногда возникают не состыковки. Т.е. я все могу понять, но не всегда в силах выразить это правильно на словах.  Строит глазки

Цитата: Igors
Если объект имеет ID, то полагается что оно уникально и двух объектов с одним ID быть не должно. Обычно указатели на такие объекты хранятся в какой-то таблице. Ну и перекрывайте конструктор копирования, оператор присваивания и деструктор чтобы обеспечить уникальность этого ID. Другой путь - для локальных объектов использовать упрощенный класс который не имеет никакого ID и имени. А у Вас мутность великая, понять мудрено   Улыбающийся  Приведите максимально упрощенный пример где возникает проблема, никак не верится что нужны такие противоестественные хуки что Вы применяете.
ID тут не причем, он и имя используется в других целях. Ясное дело, что ID у меня будут уникальными, но следить за этим я предпочел другим объектом, который его хранит. А вот насчет разделения на локи и глобалы я не совсем уверен, что будет лучше. Дело в том, что "область команд" (проще говоря список) исполняемых команд движком, имеет свои локальные переменные на которые она может указывать, путем перечисления их ID. Т.к. таких областей у меня может быть много, то проще разбивать области хранения под задачи, для которых они предназначены (как например, стек для временных переменных во время исполнения команды). Вдобавок, делать описанное вами будет излишне, т.к. у меня происходят обработка не только операции +, /, и т.д., а еще и операция присвоения. Тогда совсем логично, что ни ID, ни имя у временной переменной нет и быть не должно, а при присвоении ее значения присваиваемой переменной, остается только переменная, которой присвоили. Поэтому, ни операторы +, / и т.д., ни контроль ID мне внутри класса не нужен. Тем более, что проще объединить константные значения, переменные, временные переменные в один класс, т.к. по сути они одинаковы в своих значениях, а большего при операции над ними не требуется.

З.Ы.
Можеть я не так понял смысл вашего поста, но по мне вы начали думать о интерпретаторах, что несколько выходит за рамки темы.  Подмигивающий
Записан
Eten
Гость
« Ответ #31 : Март 07, 2011, 15:48 »

Не спорю, что всего заранее не предусмотреть. Но, "заложить фундамент" я понимаю как некий основной теор. минимум: как вообще другие с подобными проблемами справлялись, есть ли отточенные решения для этой ситуации, какие инструменты ит.д.
И под архитектурой я вовсе не имею ввиду окончательный вариант, но некий интерплей между объектами, их обязанности,  иерархия, какие то свойства основные..
Короче, хотел выразить мысль, что картина вырисовывается не из-за понятий, а из взаимоотношений между ними.. Как то так))
К тому же, хуже от того, чтобы вначале подумать, взять листочек с ручкой, почеркать, походить, покурить точно не будет) 
(разве что от покурить)))
   
Я тоже продумываю все на листке бумаги, но всегда знаю, что может получиться криво. Ибо вначале, никак без этого, всегда где-нибудь не хватить знаний или опыта.  Подмигивающий Но вот иерархия для класса NNumeric у меня вышла такая, какая она есть. И я не нашел пока причин ее переделывать иначе, мне пока этого варианта хватает. Все остальное подчиненно именно постановке задачи и того, что требуется. Т.е., если написаны переопределенные операторы, значит при исходном (без них) варианте, они мне понадобились, чтобы сохранить исходный вариант записи при добавлении операций с "*". Все, как учил дядька Страустрап.  Подмигивающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #32 : Март 07, 2011, 16:07 »

Не спорю, что всего заранее не предусмотреть. Но, "заложить фундамент" я понимаю как некий основной теор. минимум: как вообще другие с подобными проблемами справлялись, есть ли отточенные решения для этой ситуации, какие инструменты ит.д.
Хммм.. ну как сказать, "дело тонкое". Мне часто приходится делать задачи которые имеют аналоги, т.е. уже не раз делались. Но это совсем не Assistant где уже готовые/отточенные решения. Конечно, всегда хочется "прикрутить готовое" - но вот получается редко  Улыбающийся Смотришь - вроде исходники (часто open-source) грамотные, ладно, рискну. А через неделю-две начинаешь понимать что (несмотря на "формальную грамотность") программист тупенько передрал такую-то статью. А что оно работает "до первого милиционера", что никакие граничные случаи не отрабатываются, да и вообще сам алгоритм слабоват - так его это не волновало. Чтобы не быть голословным, вот примерчик (Вы templae любите)

http://www.csie.ntu.edu.tw/~cyy/courses/rendering/pbrt-2.00/html/octree_8h_source.html

Где с первого взгляда все гладко/хорошо - но это не так
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #33 : Март 07, 2011, 16:10 »

Не спорю, что всего заранее не предусмотреть. Но, "заложить фундамент" я понимаю как некий основной теор. минимум: как вообще другие с подобными проблемами справлялись, есть ли отточенные решения для этой ситуации, какие инструменты ит.д.
И под архитектурой я вовсе не имею ввиду окончательный вариант, но некий интерплей между объектами, их обязанности,  иерархия, какие то свойства основные..
Короче, хотел выразить мысль, что картина вырисовывается не из-за понятий, а из взаимоотношений между ними.. Как то так))
К тому же, хуже от того, чтобы вначале подумать, взять листочек с ручкой, почеркать, походить, покурить точно не будет)  
(разве что от покурить)))
  
Я тоже продумываю все на листке бумаги, но всегда знаю, что может получиться криво. Ибо вначале, никак без этого, всегда где-нибудь не хватить знаний или опыта.  Подмигивающий Но вот иерархия для класса NNumeric у меня вышла такая, какая она есть. И я не нашел пока причин ее переделывать иначе, мне пока этого варианта хватает. Все остальное подчиненно именно постановке задачи и того, что требуется. Т.е., если написаны переопределенные операторы, значит при исходном (без них) варианте, они мне понадобились, чтобы сохранить исходный вариант записи при добавлении операций с "*". Все, как учил дядька Страустрап.  Подмигивающий
Не думаете ли Вы, что задуманная Вами архитектура единствена?
Я хочу сказать, что нужно учится выбирать правильные решения, а не решения, которые направлены на обход граблей.
Я тоже согласен с brankovic, что введение таких сомнительных операторов только запутывают логику и программу - это грабли, на которые кто-нить да наступит..

А можно, если не сложно, описать для чего всё это нужно и как по Вашему это всё работает и почему это должно быть именно так?
Вобщем описание проблемы не могли бы изложить?  
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #34 : Март 07, 2011, 16:19 »

Не спорю, что всего заранее не предусмотреть. Но, "заложить фундамент" я понимаю как некий основной теор. минимум: как вообще другие с подобными проблемами справлялись, есть ли отточенные решения для этой ситуации, какие инструменты ит.д.
Хммм.. ну как сказать, "дело тонкое". Мне часто приходится делать задачи которые имеют аналоги, т.е. уже не раз делались. Но это совсем не Assistant где уже готовые/отточенные решения. Конечно, всегда хочется "прикрутить готовое" - но вот получается редко  Улыбающийся Смотришь - вроде исходники (часто open-source) грамотные, ладно, рискну. А через неделю-две начинаешь понимать что (несмотря на "формальную грамотность") программист тупенько передрал такую-то статью. А что оно работает "до первого милиционера", что никакие граничные случаи не отрабатываются, да и вообще сам алгоритм слабоват - так его это не волновало. Чтобы не быть голословным, вот примерчик (Вы templae любите)

http://www.csie.ntu.edu.tw/~cyy/courses/rendering/pbrt-2.00/html/octree_8h_source.html

Где с первого взгляда все гладко/хорошо - но это не так

Я бы не стал это использовать.. Я всегда с большим подозрением отношусь к подобным конструкциям:
Код
C++ (Qt)
template <typename NodeData> struct OctNode {
00037     OctNode() {
00038         for (int i = 0; i < 8; ++i)
00039             children[i] = NULL;
00040     }
00041     ~OctNode() {
00042         for (int i = 0; i < 8; ++i)
00043             delete children[i];
00044     }
00045     OctNode *children[8];
00046     vector<NodeData> data;
00047 };
 
Когда вот так просто открытые указатели объявляют..
Это не в традициях C++
хотя впрочем этот класс у них явно нигде не пресутствует.. Не знаю, тут разбираться надо..
Просто это первое, что в глаза попало..
« Последнее редактирование: Март 07, 2011, 16:39 от m_ax » Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #35 : Март 07, 2011, 16:22 »

но по своему опыту знаю, что отношусь к тем людям, у которых понимание опережает формулирование мыслей. Из-за этого иногда возникают не состыковки.
Насколько могу судить о себе, я принадлежу к именно такому типу людей  Улыбающийся Но как ни крути, а задачу формулировать надо. Вы же даете/публикуете только свои выводы, они могут быть верны или нет, но совершенно непонятно к какой задаче/цели они относятся  Улыбающийся
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #36 : Март 07, 2011, 16:47 »

Когда вот так просто открытые указатели объявляют..
Это не в традициях C++
хотя впрочем этот класс у них явно нигде не пресутствует.. Не знаю, тут разбираться надо..
Просто это первое, что в глаза попало..
Ну то "дело вкуса". Я спокойно отношусь к открытым членам класса, если Вы нет - никто не мешает сделать это private, код-то открыт. А вот принципиально что эта реализация (как и многие др) имеет жестокие пробои в ф-циональности и, по существу, пригодна лишь для студенческого курсового (так, абы було, отчитаться)
Записан
brankovic
Гость
« Ответ #37 : Март 07, 2011, 17:08 »

brankovic, спасибо, но я уже это понял, когда вы намекнули про утечку (этот момент я тоже исправил), поэтому там, где у себя лишним поставил деструктор для dt, его же и убрал. Работу с указателями привел потому, что вы спрашивали.

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

std::vectror <NNumeric *> stack;

я могу вместо этого спокойно использовать

std::vector <NNumeric> stack;

Но пусть даже будет NNuberic *, тогда функцию pop () можно написать примерно так:

Код
C++ (Qt)
NNumeric Stack::pop ()
{
  NNumeric tmp = *m_stack.back ();
  delete m_stack.back ();
  m_stack.pop_back ();
  return tmp;
}
 

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

То есть вопрос такой: по какой причине для NNumeric вообще нужно хоть раз использовать оператор new?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #38 : Март 07, 2011, 17:18 »

Вот, например, я храню

std::vectror <NNumeric *> stack;

я могу вместо этого спокойно использовать

std::vector <NNumeric> stack;
Если Eten связался с ID и "уникальностью" экземпляров - то нет, практически он вынужден работать по указателю. Конечно не беда, но зачем создавать причудливые конструкции?
Записан
Eten
Гость
« Ответ #39 : Март 07, 2011, 17:50 »

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

А можно, если не сложно, описать для чего всё это нужно и как по Вашему это всё работает и почему это должно быть именно так?
Вобщем описание проблемы не могли бы изложить?  
Единственная врятли, т.к. идея всегда одна, вариантов море. Надо только понимать, что выбрав один вариант, как основную линию, всегда практичней ее придерживаться, нежели брать обрывки из различных вариантов. Попытка взять все самое лучшее из других вариантов, по сути еще один вариант.  Подмигивающий

Насчет сомнительных операторов со "*", сомнения отпадают, когда приходится работать с указателями для хранения объектов, через базовые. Ситуации, где бы я мог передать указателю адрес из стека и рулить им в указателе на базовый класс я не встречал, а учитывая, что объект в программе используется только одним способом (вариантом), то для способов он не подходит. Полагаю, что именно абзацем ниже стоит объяснить почему.

Для начало повторюсь, что класс NNumeric (ровно как и другие) чисто хранит в себе значение и дополнительную информацию нужную движку-исполнителю. Который в свою очередь обеспечивает работу с такими типами данных, как NNumeric. Т.е. движок - это исполнитель входного кода в виде команд. Он осуществляет операции с экземплярами NNumeric и хранит из в виде указателей на базовый класс. Базовые классы используются не только для хранения, но для группирования классов по иерархии, т.к. есть классы сложнее NNumeric и использующие его для хранения чисел. Т.к. класс NNumeric используется для хранения и конструктор копирования по ссылке и также оператор присваивания по умолчанию копируют члены из экземпляра  одного в другой, то намного практичнее было сделать класс NNumeric именно принимающим значения, а не выполняющим переопределенные операторы для арифметики. Т.к. он спокойно может выдать свое значение с учетом типа, в который преобразуется. А дальше обычные действия. Т.к. в основном операции идут, через тип double и не могут пересечь ее границ (из-за границ установленных в классе, так и из-за границ самого типа float, т.к. получаем числа из файлов в виде 4 байт), то удобней применять его в качестве параметра автоматического конструктора и осуществлять контроль границ уже внутри класса. Сами типы float и qint32 также выдаются, но чисто для записи в файл или на вывод, но qint32 также используется в целочисленных операциях вместо double. Естественно для контроля целое/не целое есть _isreal, с помощью которого движок осуществляет правильное преобразование значений в нужный тип данных. Т.о. преобладает использование класса NNumeric  без указателя. Но, т.к. нигде не было встречено работы базовых классов с производными без указатели в СИ++, то необходимо использовать указатели на базовый класс. Но указатели на базовый класс приводятся к указателям на класс NNumeric, а переопределенные операторы (т.е. те, что имеют в классе) и работают с экземпляром NNumeric, а не указателем на класс NNumeric. Поэтому потребовалось сохранить работу с экземплярами NNumeric, а указатели использовать только чисто для хранения, но оперировать только лишь экземплярами NNumeric. Тем более, что передавая т.о., как описано в классе NNumeric мы не трогаем хранящиеся переменные, константные значения и временные переменные (хотя эти врятли, т.к. они попадают только в QStack). Т.к. при таком подходе обрывается связь с тем место, откуда был взят экземпляр, как если бы я работал через QVariant. А мне именно это и нужно, чтобы не затрагивать место хранения. С другой стороны, просто так указателю на класс не присвоишь экземпляр класса, т.к. работать с указателем ссылающимся на экземпляр класса объявленного не в куче, а в стеке вызывает очевидные проблемы. Следовательно, нужно по отдельно использовать все set функции для передачи хранящейся информации из экземпляра в указатель на класса, предварительно вызвав конструктор для указателя на класс. Этот указатель мы и сохраняем в указатель на базовый класс. Получается следующая ситуация, у нас много операций с экземплярами и нам придется повторить такое же кол-во раз, сколько и самих экземпляров используется, отсюда могут полезть ошибки и получится использование одного и того же кода два и более раз. Поэтому, практичнее сократить форму записи прописав все это в преобразование в NNumeric*, т.к. при наличии подобного переопределенного оператора он используется при попытке экземпляр класса присвоить указателю на этот класс или базовый для него. Т.о. мне практически ничего не надо было переписывать в функции матем. операций. Но одна сторона медали, а теперь другая. Т.к. для вывода и прочих операций опять используются только экземпляры класса NNumeric, то и здесь указатели не нужны. Но, хранится то у нас это все в указателях на базовый класс и даже после приведения к классу, это опять же указатель на класс, а нам нужны экземпляры. Опять же возникнет многократное вызывание функций set у класса NNumeric и опять тоже самое, что и в случае с передачей значений из указателя в экземпляр класса. Опять же все это прописываем в классе перегружая конструтор копирования, который по сути просто копирует значения, но внутри себя, и оператор присваивания, который по сути выполняет тоже самое. Но есть одно "но", однако здесь тоже самое, что и с конструктором копирования по ссылке и такому же оператору присвоения. Т.е. в одних случая идет присвоение, в других инициализация. Вот и получается, что таким переопределением определенных операторов и конструкторов я могу спокойно пользоваться экземплярами класса, а при передачи их в место хранения они сами выдадут указатель на класс созданный в куче, а не в стеке. А также при взятии из места хранения мне нет нужды исписывать километры строк для передачи значений в экземпляр класса. При этом не затрагивается как место хранения при работе с указателями, так и сами значения при выполнении операций над экземплярами класса. Говоря иначе, указатели для хранения с использованием базовых классов, ибо без указателей здесь никак.
Записан
Eten
Гость
« Ответ #40 : Март 07, 2011, 17:52 »

Вот, например, я храню

std::vectror <NNumeric *> stack;

я могу вместо этого спокойно использовать

std::vector <NNumeric> stack;
Если Eten связался с ID и "уникальностью" экземпляров - то нет, практически он вынужден работать по указателю. Конечно не беда, но зачем создавать причудливые конструкции?
Igors, ну вы же не будете думать, что я взял и создал иерархию классов только для одного класса NNumeric?! У меня там хранятся все производные от NDataTypes классы.

И честно говоря, у меня в программе они так быть использованы, как у вас не могут. Они не для такого применения задуманы.  Подмигивающий
« Последнее редактирование: Март 07, 2011, 17:56 от Eten » Записан
Eten
Гость
« Ответ #41 : Март 07, 2011, 18:02 »

Ладно, приложу еще одну функцию:
Код
C++ (Qt)
void NeorgekEngine::NEngine::MathematicalOperations(ushort Modifikator)
{
   NNumeric arg0, arg1, arg2;
   NDataTypes* dt;
 
   switch (Modifikator)
   {
       case 2:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (!arg1.IsReal() && !arg2.IsReal())
           {
                arg0.setIsReal(false);
                arg0.setValue(double(arg1) + double(arg2));
           }
           else
               arg0 = double(arg1) + double(arg2);
 
           this->StackValue.push(arg0);
       break;
       case 3:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (!arg1.IsReal() && !arg2.IsReal())
           {
               arg0.setIsReal(false);
               arg0.setValue(double(arg1) - double(arg2));
           }
           else
               arg0 = double(arg1) - double(arg2);
 
           this->StackValue.push(arg0);
       break;
       case 4:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (!arg1.IsReal() && !arg2.IsReal())
           {
               arg0.setIsReal(false);
               arg0.setValue(double(arg1) * double(arg2));
           }
           else
               arg0 = double(arg1) * double(arg2);
 
           this->StackValue.push(arg0);
       break;
       case 5:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           //if (arg2 == 0)
 
           if (!arg1.IsReal() && !arg2.IsReal())
           {
               arg0.setIsReal(false);
               arg0.setValue(double(arg1) / double(arg2));
           }
           else
               arg0 = double(arg1) / double(arg2);
 
           this->StackValue.push(arg0);
       break;
       case 6:
           dt = this->StackValue.pop();
           arg0 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0++;
           arg0.setID(-1);
           arg0.setConstValue(false);
           arg0.setName("");
 
           this->StackValue.push(arg0);
       break;
       case 7:
           dt = this->StackValue.pop();
           arg0 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0--;
           arg0.setID(-1);
           arg0.setConstValue(false);
           arg0.setName("");
 
           this->StackValue.push(arg0);
       break;
       case 8:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0.setIsReal(false);
           arg0.setValue((ldiv(qint32(arg1), qint32(arg2)).quot));
 
           this->StackValue.push(arg0);
       break;
       case 9:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0.setIsReal(false);
           arg0.setValue((ldiv(qint32(arg1), qint32(arg2)).rem));
 
           this->StackValue.push(arg0);
       break;
       case 10:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (!arg1.IsReal() && !arg2.IsReal())
           {
                arg0.setIsReal(false);
                arg0.setValue(pow(double(arg1),double(arg2)));
           }
           else
               arg0 = pow(double(arg1),double(arg2));
 
           this->StackValue.push(arg0);
       break;
       case 11:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (!arg1.IsReal())
           {
               arg0.setIsReal(false);
               arg0.setValue(sqrt(double(arg1)));
           }
           else
               arg0 = sqrt(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 12:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0.setIsReal(arg1.IsReal());
           arg0.setValue(std::abs(double(arg1)));
 
           this->StackValue.push(arg0);
       break;
       case 13:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (double(arg1) < double(arg2)) arg0 = arg1; else arg0 = arg2;
 
           arg0.setID(-1);
           arg0.setConstValue(false);
           arg0.setName("");
 
           this->StackValue.push(arg0);
       break;
       case 14:
           dt = this->StackValue.pop();
           arg2 = dynamic_cast<NNumeric*>(dt);
           delete dt;
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           if (double(arg1) > double(arg2)) arg0 = arg1; else arg0 = arg2;
 
           arg0.setID(-1);
           arg0.setConstValue(false);
           arg0.setName("");
 
           this->StackValue.push(arg0);
       break;
       case 15:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           srand ( time(NULL) );
           arg0.setIsReal(false);
           arg0.setValue(qint32(rand() % qint32(arg1)));
 
           this->StackValue.push(arg0);
       break;
       case 16:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = log10(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 17:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = log(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 18:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = exp(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 19:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = cos(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 20:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = sin(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 21:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = tan(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 22:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = 1.0/tan(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 23:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = acos(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 24:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = asin(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 25:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = atan(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 26:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = 1.0/atan(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 27:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = floor(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 28:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = ceil(double(arg1));
 
           this->StackValue.push(arg0);
       break;
       case 29:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = arg1.round();
 
           this->StackValue.push(arg0);
       break;
       case 30:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = arg1.fractional();
 
           this->StackValue.push(arg0);
       break;
       case 31:
           dt = this->StackValue.pop();
           arg1 = dynamic_cast<NNumeric*>(dt);
           delete dt;
 
           arg0 = arg1.integer();
 
           this->StackValue.push(arg0);
       break;
       case 32:
 
           srand ( time(NULL) );
           arg0 = double(rand() % 1001)/1000.0;
 
           this->StackValue.push(arg0);
       break;
   }
}
 

Вопрос, как это (см. код выше) можно записать без применения тех трех макроопределений с NNumeric*, а ведь это только малая часть движка?  Подмигивающий

З.Ы.
Честно, я все никак не могу понять, почему вы их называете хаками, ведь я ничего противоестественного не делаю с самими операторами и конструктором, т.е. использую их как по обычному без переопределенний, всего лишь сократил себе лишние строки в коде.  Непонимающий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #42 : Март 07, 2011, 19:36 »

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

Цитировать
- Цигане, посунься будь ласка
- Я афро-американец, а не цыган
- O! То якi в вас мають бути цигани? 
Если Вы считаете что так Вы "ничего плохого" не делаете, то что ж будет когда сделаете?  Улыбающийся

case 2:
            dt = this->StackValue.pop();
            arg2 = dynamic_cast<NNumeric*>(dt);
            delete dt;
            dt = this->StackValue.pop();
            arg1 = dynamic_cast<NNumeric*>(dt);
            delete dt;
 
            if (!arg1.IsReal() && !arg2.IsReal())
            {
                 arg0.setIsReal(false);
                 arg0.setValue(double(arg1) + double(arg2));
            }
            else
                arg0 = double(arg1) + double(arg2);
 
            this->StackValue.push(arg0);
        break;
Нормальный программист "рефлекторно" стремится записать это одной строкой, напр.

Код
C++ (Qt)
case NNumeric::operation_plus:
stack.push(stack.pop_value() + stack.pop_valie());
break;
 
Где pop_value просто так

Код
C++ (Qt)
NNumeric Stack::pop_value( void )
{
if (!size()) throw "stack error";
NNumeric * temp = pop();
NNumeric value(*temp);
delete temp;
return value;
}
 

И еще. Не хотелось начинать неприятный разговор, но приходится. Перлы типа

Цитировать
case 2: // видимо Вам еще не приходилось "откапывать" это 2 и вспоминать маму написавшего
..
case 32:

StackValie (с большой буквы и совсем не "value")
С полным правом могут расцениваться как прямое неуважение к собеседникам и к форуму вообще. Так можно писать "на первенство двора", но не в приличном обществе. Извольте оформить все как положено, иначе - будьте здоровы .

Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #43 : Март 07, 2011, 20:00 »

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

А можно, если не сложно, описать для чего всё это нужно и как по Вашему это всё работает и почему это должно быть именно так?
Вобщем описание проблемы не могли бы изложить?  
Единственная врятли, т.к. идея всегда одна, вариантов море. Надо только понимать, что выбрав один вариант, как основную линию, всегда практичней ее придерживаться, нежели брать обрывки из различных вариантов. Попытка взять все самое лучшее из других вариантов, по сути еще один вариант.  Подмигивающий

Насчет сомнительных операторов со "*", сомнения отпадают, когда приходится работать с указателями для хранения объектов, через базовые. Ситуации, где бы я мог передать указателю адрес из стека и рулить им в указателе на базовый класс я не встречал, а учитывая, что объект в программе используется только одним способом (вариантом), то для способов он не подходит. Полагаю, что именно абзацем ниже стоит объяснить почему.

Для начало повторюсь, что класс NNumeric (ровно как и другие) чисто хранит в себе значение и дополнительную информацию нужную движку-исполнителю. Который в свою очередь обеспечивает работу с такими типами данных, как NNumeric. Т.е. движок - это исполнитель входного кода в виде команд. Он осуществляет операции с экземплярами NNumeric и хранит из в виде указателей на базовый класс. Базовые классы используются не только для хранения, но для группирования классов по иерархии, т.к. есть классы сложнее NNumeric и использующие его для хранения чисел. Т.к. класс NNumeric используется для хранения и конструктор копирования по ссылке и также оператор присваивания по умолчанию копируют члены из экземпляра  одного в другой, то намного практичнее было сделать класс NNumeric именно принимающим значения, а не выполняющим переопределенные операторы для арифметики. Т.к. он спокойно может выдать свое значение с учетом типа, в который преобразуется. А дальше обычные действия. Т.к. в основном операции идут, через тип double и не могут пересечь ее границ (из-за границ установленных в классе, так и из-за границ самого типа float, т.к. получаем числа из файлов в виде 4 байт), то удобней применять его в качестве параметра автоматического конструктора и осуществлять контроль границ уже внутри класса. Сами типы float и qint32 также выдаются, но чисто для записи в файл или на вывод, но qint32 также используется в целочисленных операциях вместо double. Естественно для контроля целое/не целое есть _isreal, с помощью которого движок осуществляет правильное преобразование значений в нужный тип данных. Т.о. преобладает использование класса NNumeric  без указателя. Но, т.к. нигде не было встречено работы базовых классов с производными без указатели в СИ++, то необходимо использовать указатели на базовый класс. Но указатели на базовый класс приводятся к указателям на класс NNumeric, а переопределенные операторы (т.е. те, что имеют в классе) и работают с экземпляром NNumeric, а не указателем на класс NNumeric. Поэтому потребовалось сохранить работу с экземплярами NNumeric, а указатели использовать только чисто для хранения, но оперировать только лишь экземплярами NNumeric. Тем более, что передавая т.о., как описано в классе NNumeric мы не трогаем хранящиеся переменные, константные значения и временные переменные (хотя эти врятли, т.к. они попадают только в QStack). Т.к. при таком подходе обрывается связь с тем место, откуда был взят экземпляр, как если бы я работал через QVariant. А мне именно это и нужно, чтобы не затрагивать место хранения. С другой стороны, просто так указателю на класс не присвоишь экземпляр класса, т.к. работать с указателем ссылающимся на экземпляр класса объявленного не в куче, а в стеке вызывает очевидные проблемы. Следовательно, нужно по отдельно использовать все set функции для передачи хранящейся информации из экземпляра в указатель на класса, предварительно вызвав конструктор для указателя на класс. Этот указатель мы и сохраняем в указатель на базовый класс. Получается следующая ситуация, у нас много операций с экземплярами и нам придется повторить такое же кол-во раз, сколько и самих экземпляров используется, отсюда могут полезть ошибки и получится использование одного и того же кода два и более раз. Поэтому, практичнее сократить форму записи прописав все это в преобразование в NNumeric*, т.к. при наличии подобного переопределенного оператора он используется при попытке экземпляр класса присвоить указателю на этот класс или базовый для него. Т.о. мне практически ничего не надо было переписывать в функции матем. операций. Но одна сторона медали, а теперь другая. Т.к. для вывода и прочих операций опять используются только экземпляры класса NNumeric, то и здесь указатели не нужны. Но, хранится то у нас это все в указателях на базовый класс и даже после приведения к классу, это опять же указатель на класс, а нам нужны экземпляры. Опять же возникнет многократное вызывание функций set у класса NNumeric и опять тоже самое, что и в случае с передачей значений из указателя в экземпляр класса. Опять же все это прописываем в классе перегружая конструтор копирования, который по сути просто копирует значения, но внутри себя, и оператор присваивания, который по сути выполняет тоже самое. Но есть одно "но", однако здесь тоже самое, что и с конструктором копирования по ссылке и такому же оператору присвоения. Т.е. в одних случая идет присвоение, в других инициализация. Вот и получается, что таким переопределением определенных операторов и конструкторов я могу спокойно пользоваться экземплярами класса, а при передачи их в место хранения они сами выдадут указатель на класс созданный в куче, а не в стеке. А также при взятии из места хранения мне нет нужды исписывать километры строк для передачи значений в экземпляр класса. При этом не затрагивается как место хранения при работе с указателями, так и сами значения при выполнении операций над экземплярами класса. Говоря иначе, указатели для хранения с использованием базовых классов, ибо без указателей здесь никак.
Млин, я честно пречитал это раза три, но нифига не понял  Грустный
Лучше опишите суть задачи, которую Вы пытаетесь реализовать.. (как можно проще и понятнее, на пальцах можно сказать)
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Eten
Гость
« Ответ #44 : Март 07, 2011, 23:05 »

case 2:
            dt = this->StackValue.pop();
            arg2 = dynamic_cast<NNumeric*>(dt);
            delete dt;
            dt = this->StackValue.pop();
            arg1 = dynamic_cast<NNumeric*>(dt);
            delete dt;
 
            if (!arg1.IsReal() && !arg2.IsReal())
            {
                 arg0.setIsReal(false);
                 arg0.setValue(double(arg1) + double(arg2));
            }
            else
                arg0 = double(arg1) + double(arg2);
 
            this->StackValue.push(arg0);
        break;
Нормальный программист "рефлекторно" стремится записать это одной строкой, напр.

Код
C++ (Qt)
case NNumeric::operation_plus:
stack.push(stack.pop_value() + stack.pop_valie());
break;
 
Где pop_value просто так

Код
C++ (Qt)
NNumeric Stack::pop_value( void )
{
if (!size()) throw "stack error";
NNumeric * temp = pop();
NNumeric value(*temp);
delete temp;
return value;
}
 

И еще. Не хотелось начинать неприятный разговор, но приходится. Перлы типа

Цитировать
case 2: // видимо Вам еще не приходилось "откапывать" это 2 и вспоминать маму написавшего
..
case 32:

StackValie (с большой буквы и совсем не "value")
С полным правом могут расцениваться как прямое неуважение к собеседникам и к форуму вообще. Так можно писать "на первенство двора", но не в приличном обществе. Извольте оформить все как положено, иначе - будьте здоровы .
Не знаю, откуда у вас взялся StackValie, но у меня его в коде отродясь не было, иначе не работало б тогда. И приведенные здесь коды взяты с исходников, так что опечаток подобных у меня нету.  Подмигивающий Насчет упомянки про case 2, каюсь совсем забыл. Вот как раз выдержка из памятки:
Код:
Модификатор	Комментарий
2 +
3 -
4 *
5 /
6 ++
7 --
8 целочисленное деление
9 % (остаток от целочисленного деления)
10 ^
11 квадратный корень
12 модуль числа
13 минимальное число
14 максимальное число
15 целочисленный рандом от 0 и до m-1
16 log10
17 ln
18 exp
19 cos
20 sin
21 tg
22 ctg
23 arccos
24 arcsin
25 arctg
26 arcctg
27 округление в сторону нуля до целого
28 округление в большую сторону до целого
29 округление до целого
30 выделение дробной части
31 отсечение дробной части
32 рандом от 0 до 1
В плане не уважения, ни кого обидеть не хотел, но что-то мне приходится часто таскать из темы в тему свой класс. Правильно ли я поступаю?  В замешательстве

Да, кстати, а почему вы мне все время указывает на то, что я с большой буквы начинаю? В этом нет ничего плохого, т.к. есть два общепринятых стиля. Один из них, который указывали вы и другие, а другой я сам использую. Что-то я не припомню, что был только один стиль.  Подмигивающий

Насчет сократить код до одной строки мысль интересная, но не везде годная. Это я еще в функции MathematicalOperations обработку на особые ситуации не прописывал (надо до этого прописать и реализовать кое-что еще). Например в case 7, это у вас никак не выйдет. Но все равно спасибо.  Подмигивающий

З.Ы.
Про автобус рассмешило, но ситуация с хаками для все равно, что вопрос для человека из древности: "Земля вокруг Солнца или Солнце вокруг Земли движется".  Строит глазки

З.З.Ы.
m_ax, я понимаю, что возможно написал сложновато или увлекся, но сегодня уже никак, давайте завтра. Утро, вечера мудренее.  Подмигивающий
« Последнее редактирование: Март 07, 2011, 23:16 от Eten » Записан
Страниц: 1 2 [3] 4 5 6   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.237 секунд. Запросов: 23.