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

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

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

Фух, только что переписал до конца (разумеется выспавшись  Подмигивающий ) на стиль Си++ оформление везде в своей проге, плюс сделал полную инкапсуляцию класса NNumeric. Заодно, оказалось, что проблем при работе с местом хранения (т.е. запись в места хранения) полная инкапсуляция мне не создает. Плюс ко всему этому, обеспечил класс NNumeric статическими математическими функциями, которые для него допустимы исходя из ТЗ программы. Т.е. работает, как и раньше, только код стал удобным, читабельным и компактным.

Базовые классы для NNumeric:
Код
C++ (Qt)
#include <QString>
 
   class NDataTypes
   {
   public:
       NDataTypes() {_id = -1; _name = "";}
       virtual ~NDataTypes() { }
 
       qint32 id() const {return _id;}
       void setId(qint32 id) {_id = id;}
       QString name() const {return _name;}
       void setName(QString name) {if (name != NULL) _name = name; else _name = "";}
 
   protected:
       //если идентификатор равен -1, значит это либо временная переменная, либо константное значение
       qint32 _id;
       //константные или временные значения имен не имеют, только переменные.
       QString _name;
 
   };
 
   class NSimpleDataTypes : public NDataTypes
   {
   public:
       NSimpleDataTypes() : NDataTypes() {_constValue = false;}
 
       bool constValue() const {return _constValue;}
       void setConstValue(bool constValue) {_constValue = constValue;}
 
   protected:
       //это указывает на константное значение
       bool _constValue;
   };
 

Сам класс NNuemric:
Код
C++ (Qt)
class NNumeric : public NSimpleDataTypes
{
public:
 
   NNumeric(double value = 0)
       : NSimpleDataTypes()
   {
       _isTypeInteger = false;
       setValue(value);
   }
 
   NNumeric(double value, bool isTypeInteger)
           : NSimpleDataTypes()
   {
       setisTypeInteger(isTypeInteger);
       setValue(value);
   }
 
 
   //целочисленное деление
   static NNumeric nnDiv(NNumeric a, NNumeric b)
   {
       return NNumeric(ldiv(qint32(a), qint32(b)).quot, true);
   }
 
   //% (остаток от целочисленного деления)
   static NNumeric nnMod(NNumeric a, NNumeric b)
   {
       return NNumeric(ldiv(qint32(a), qint32(b)).rem, true);
   }
 
   //возведение в степень
   static NNumeric nnPow(NNumeric a, NNumeric b)
   {
       return NNumeric(pow(double(a), double(b)), a.isTypeInteger() && b.isTypeInteger());
   }
 
   //квадратный корень
   static NNumeric nnSqrt(NNumeric a)
   {
       return NNumeric(sqrt(double(a)), a.isTypeInteger());
   }
 
   //модуль числа
   static NNumeric nnAbs(NNumeric a)
   {
       return NNumeric(std::abs(double(a)), a.isTypeInteger());
   }
 
   //минимальное число
   static NNumeric nnMin(NNumeric a, NNumeric b)
   {
       double d1 = double(a), d2 = double(b);
       return d1 < d2 ? NNumeric(d1, a.isTypeInteger()) : NNumeric(d2, b.isTypeInteger());
   }
 
   //максимальное число
   static NNumeric nnMax(NNumeric a, NNumeric b)
   {
       double d1 = double(a), d2 = double(b);
       return d1 > d2 ? NNumeric(d1, a.isTypeInteger()) : NNumeric(d2, b.isTypeInteger());
   }
 
   //десятичный логарифм
   static NNumeric nnLog10(NNumeric a)
   {
       return NNumeric(log10(double(a)));
   }
 
   //натуральный логарифм
   static NNumeric nnLog(NNumeric a)
   {
       return NNumeric(log(double(a)));
   }
 
   //экспонента в степени "a"
   static NNumeric nnExp(NNumeric a)
   {
       return NNumeric(exp(double(a)));
   }
 
   //косинус
   static NNumeric nnCos(NNumeric a)
   {
       return NNumeric(cos(double(a)));
   }
 
   //синус
   static NNumeric nnSin(NNumeric a)
   {
       return NNumeric(sin(double(a)));
   }
 
   //тангенс
   static NNumeric nnTan(NNumeric a)
   {
       return NNumeric(tan(double(a)));
   }
 
   //арктангенс
   static NNumeric nnCtan(NNumeric a)
   {
       return NNumeric(1.0 / tan(double(a)));
   }
 
   //арккосинус
   static NNumeric nnACos(NNumeric a)
   {
       return NNumeric(acos(double(a)));
   }
 
   //арксинус
   static NNumeric nnASin(NNumeric a)
   {
       return NNumeric(asin(double(a)));
   }
 
   //арктангенс
   static NNumeric nnATan(NNumeric a)
   {
       return NNumeric(atan(double(a)));
   }
 
   //арккатангенс
   static NNumeric nnACtan(NNumeric a)
   {
       return NNumeric(1.0 / atan(double(a)));
   }
 
   //округление в сторону нуля до целого
   static NNumeric nnFloor(NNumeric a)
   {
       return NNumeric(floor(double(a)));
   }
 
   //округление в большую сторону до целого
   static NNumeric nnCeil(NNumeric a)
   {
       return NNumeric(ceil(double(a)));
   }
 
   //округление до целого
   static NNumeric nnRound(NNumeric a)
   {
       return NNumeric(floor(double(a) + 0.5));
   }
 
   //выделение дробной части
   static NNumeric nnFractional(NNumeric a)
   {
       double d = double(a);
       return d < 0.0 ? NNumeric(d - ceil(d)) : NNumeric(d - floor(d));
   }
 
   //отсечение дробной части
   static NNumeric nnInteger(NNumeric a)
   {
       double d = double(a);
       return d < 0.0 ? NNumeric(ceil(d)) : NNumeric(floor(d));
   }
 
   //целочисленный рандом от 0 и до a-1
   static NNumeric nnRandom(NNumeric a)
   {
       srand ( time(NULL) );
       return NNumeric(rand() % qint32(a), false);
   }
 
   //рандом от 0 до 1
   static NNumeric nnRnd()
   {
       srand ( time(NULL) );
       return NNumeric(double(rand() % 1001)/1000.0);
   }
 
 
   NNumeric operator+(NNumeric b)
   {
       return NNumeric(this->value() + b.value(), this->isTypeInteger() && b.isTypeInteger());
   }
 
   NNumeric operator-(NNumeric b)
   {
       return NNumeric(this->value() - b.value(), this->isTypeInteger() && b.isTypeInteger());
   }
 
   NNumeric operator*(NNumeric b)
   {
       return NNumeric(this->value() * b.value(), this->isTypeInteger() && b.isTypeInteger());
   }
 
   NNumeric operator/(NNumeric b)
   {
       return NNumeric(this->value() / b.value(), this->isTypeInteger() && b.isTypeInteger());
   }
 
   void operator++(int)
   {
       if (isTypeInteger())
           _value = checkingInt32Borders(_value + 1);
       else
           _value = checkingFloatBorders(_value + 1);
   }
 
   void operator--(int)
   {
       if (isTypeInteger())
           _value = checkingInt32Borders(_value - 1);
       else
           _value = checkingFloatBorders(_value - 1);
   }
 
 
   operator QString() {return QString::number(_value);}
 
   operator float() {return checkingFloatBorders(value());}
 
   operator qint32() {return checkingInt32Borders(_value);}
 
   //оператор ниже позволяет передать указателю значения из экземпляра класса
   operator NNumeric*()
   {
       NNumeric* pnn = new NNumeric();
 
       pnn->setId(id());
       pnn->setConstValue(constValue());
       pnn->setName(name());
       pnn->setisTypeInteger(isTypeInteger());
       pnn->setValue(value());
 
       return pnn;
   }
 
private:
 
   long double int32Max() const {return 2147483647;}
 
   long double int32Min() const {return -2147483647;}
 
   long double floatMax() const {return 2.147483647e9;}
 
   long double floatMin() const {return 2.147483647e-9;}
 
   float checkingFloatBorders (double value) const
   {
       //В этой функции +/-inf приравниваются к max и min границам.
       double d = fabs(value);
       bool usign = value >= 0.0;
 
       if (d >= floatMax())
           return (usign) ? floatMax() : -floatMax();
 
       if (d <= floatMin() && d > 0.0)
           return (usign) ? floatMin() : -floatMin();
 
       return float(value);
   }
 
   qint32 checkingInt32Borders(double value) const
   {
       if (value >= int32Max()) return int32Max();
 
       if (value <= int32Min()) return int32Min();
 
       return qint32(value);
   }
 
 
   void setisTypeInteger(bool isTypeInteger) {_isTypeInteger = isTypeInteger;}
 
   //Если истинно, то значение принимается и выдается (при печати числа на экране)
   // с отсечение дробной части числа и соблюдением границ типа qint32.
   bool isTypeInteger() const {return _isTypeInteger;}
 
   void setValue(double value)
   {
       if (isTypeInteger())
           value = checkingInt32Borders(value);
       else
           value = checkingFloatBorders(value);
 
       _value = value;
   }
 
   double value() const {return double(checkingFloatBorders(_value));}
 
 
   operator double() {return double(checkingFloatBorders(value()));}
 
 
   double _value;
   bool _isTypeInteger;
};
 

Функция мат. операций:
Код
C++ (Qt)
void NEngine::mathematicalOperations(ushort Modifikator)
{
   NNumeric arg;
 
   switch (Modifikator)
   {
       //сумма
       case 2:
           theStack.push(popNumeric() + popNumeric());
       break;
 
       //разность
       case 3:
           theStack.push(popNumeric() - popNumeric());
       break;
 
       //умножение
       case 4:
           theStack.push(popNumeric() * popNumeric());
       break;
 
       //деление
       case 5:
           theStack.push(popNumeric() / popNumeric());
       break;
 
       //инкремент
       case 6:
           arg = popNumeric();
           arg++;
           theStack.push(arg);
       break;
 
       //декремент
       case 7:
           arg = popNumeric();
           arg--;
           theStack.push(arg);
       break;
 
       //целочисленное деление
       case 8:
           theStack.push(NNumeric::nnDiv(popNumeric(), popNumeric()));
       break;
 
       //% (остаток от целочисленного деления)
       case 9:
           theStack.push(NNumeric::nnMod(popNumeric(), popNumeric()));
       break;
 
       //возведение в степень
       case 10:
           theStack.push(NNumeric::nnPow(popNumeric(), popNumeric()));
       break;
 
       //квадратный корень
       case 11:
           theStack.push(NNumeric::nnSqrt(popNumeric()));
       break;
 
       //модуль числа
       case 12:
           theStack.push(NNumeric::nnAbs(popNumeric()));
       break;
 
       //минимальное число
       case 13:
           theStack.push(NNumeric::nnMin(popNumeric(), popNumeric()));
       break;
 
       //максимальное число
       case 14:
           theStack.push(NNumeric::nnMax(popNumeric(), popNumeric()));
       break;
 
       //целочисленный рандом от 0 и до m-1
       case 15:
           theStack.push(NNumeric::nnRandom(popNumeric()));
       break;
 
       //log10
       case 16:
           theStack.push(NNumeric::nnLog10(popNumeric()));
       break;
 
       //ln
       case 17:
           theStack.push(NNumeric::nnLog(popNumeric()));
       break;
 
       //exp
       case 18:
           theStack.push(NNumeric::nnExp(popNumeric()));
       break;
 
       //cos
       case 19:
           theStack.push(NNumeric::nnCos(popNumeric()));
       break;
 
       //sin
       case 20:
           theStack.push(NNumeric::nnSin(popNumeric()));
       break;
 
       //tg
       case 21:
           theStack.push(NNumeric::nnTan(popNumeric()));
       break;
 
       //ctg
       case 22:
           theStack.push(NNumeric::nnCtan(popNumeric()));
       break;
 
       //arccos
       case 23:
           theStack.push(NNumeric::nnACos(popNumeric()));
       break;
 
       //arcsin
       case 24:
           theStack.push(NNumeric::nnASin(popNumeric()));
       break;
 
       //arctg
       case 25:
           theStack.push(NNumeric::nnATan(popNumeric()));
       break;
 
       //arcctg
       case 26:
           theStack.push(NNumeric::nnACtan(popNumeric()));
       break;
 
       //округление в сторону нуля до целого
       case 27:
           theStack.push(NNumeric::nnFloor(popNumeric()));
       break;
 
       //округление в большую сторону до целого
       case 28:
           theStack.push(NNumeric::nnCeil(popNumeric()));
       break;
 
       //округление до целого
       case 29:
           theStack.push(NNumeric::nnRound(popNumeric()));
       break;
 
       //выделение дробной части
       case 30:
           theStack.push(NNumeric::nnFractional(popNumeric()));
       break;
 
       //отсечение дробной части
       case 31:
           theStack.push(NNumeric::nnInteger(popNumeric()));
       break;
 
       //рандом от 0 до 1
       case 32:
           theStack.push(NNumeric::nnRnd());
       break;
   }
}
 

Код
C++ (Qt)
void NEngine::writeln(qint32 id)
{
   NDataTypes* dt;
   QString str;
 
 
   if (id == 0)
   {
       dt = theStack.pop();
   }
   else
   {
       dt = variables[id-1];
   }
 
   if (typeid(NNumeric) == typeid(*dt))
   {
       NNumeric numeric = *dynamic_cast<NNumeric*>(dt);
       str = QString(numeric);
   }
 
   if (typeid(NString) == typeid(*dt))
   {
       NString string = *dynamic_cast<NString*>(dt);
       str = string.value();
   }
 
   if (typeid(NLogical) == typeid(*dt))
   {
       NLogical logical = *dynamic_cast<NLogical*>(dt);
       str = QString(logical);
   }
 
   delete dt;
   screen.setText(screen.text()+str+"<br\>");
}
 

Полагаю, что еще лучше не упрячешь. А инкремент и декремент, операции исключительного рода, поэтому их никак не свернуть и там они еще требует выполнение записи обратно (пока не реализовал).

З.Ы.
Мне уже скоро NNuemric сниться начнут.  Строит глазки
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #61 : Март 09, 2011, 12:25 »

Фух, только что переписал до конца (разумеется выспавшись  Подмигивающий )
..
З.Ы.
Мне уже скоро NNuemric сниться начнут.  Строит глазки
Должны, это нормально когда программист работает над задачей.
Переписали - намного лучше, но все равно, еще очень "рыхло" (как в ранних романах Бальзака).

NSimpleDataTypes() : NDataTypes() {_constValue = false;}
Дефаулт конструктор базового класса сам вызовется, поэтому упоминать его не нужно

case 2:
Так писать западло, Вы создаете кучу потенциальных проблем. Есть просто enum, его можно  освоить за 5-10 минут. Закоренелые С-шники предпочитают #define - тоже приемлемо но НИКОГДА не должно проходить "просто число"

с id и name нужно разбираться, здесь требуется постановка
Записан
Eten
Гость
« Ответ #62 : Март 09, 2011, 13:08 »


NSimpleDataTypes() : NDataTypes() {_constValue = false;}
Дефаулт конструктор базового класса сам вызовется, поэтому упоминать его не нужно
А как насчет того, что в Си++ все переменные нужно определять?! Будет ли у меня также, как было описано в конструкторе.


case 2:
Так писать западло, Вы создаете кучу потенциальных проблем. Есть просто enum, его можно  освоить за 5-10 минут. Закоренелые С-шники предпочитают #define - тоже приемлемо но НИКОГДА не должно проходить "просто число"

с id и name нужно разбираться, здесь требуется постановка

Насчет case у меня идет формирование команд и их модификаторов, но да, позднее у меня конечно будет сформированно перечисление модификатор, как в Qt есть (не помню точно какой, голова сейчас другим забита), т.к. определение модификатора для команд у меня будет одно единственное. Но думаю, что действительно уже пора его написать.

Насчет id и name это вы правы, но для этого мне еще нужно воссоздать некоторое кол-во классов, чтобы постановка приобрела более четкую картину представления и ее можно было бы дать прочесть другим. Но на это потребуется не мало времени.

Переписали - намного лучше, но все равно, еще очень "рыхло" (как в ранних романах Бальзака).
А можете подсказать, в чем рыхловатость?

Щас я не смогу увидеть всей рыхловатости, т.к. создаю поэтапно, но зная направление своего проекта. И при построении других классов и применения этого, я смогу заметить что-то и исправить (с напильником в руках) найденный недочет. Но некоторые подсказки, даже навскидку могут подсказать мне направления, с помощью которых я смогу увидеть то, чего можеть быть и не смог. Или то, о чем мог и не подозревать.  Подмигивающий
Записан
brankovic
Гость
« Ответ #63 : Март 09, 2011, 13:42 »

А можете подсказать, в чем рыхловатость?

лучшее враг хорошего. Для вашего уровня всё отлично. Понимание тонкостей придёт с опытом

P.S.: если Igors сказал всего лишь рыхловатый, то в моём представлении это где-то между 4+ и 5- Улыбающийся
Записан
Eten
Гость
« Ответ #64 : Март 09, 2011, 14:03 »

а-а-а-а, а то я уже подумал много чего. Но теперь буду заранее помнить, что если сначала (при первом представлении класса) не вышло, еще не значит, что потом не смогу инкапсулировать. Т.е. сначало у меня это не получалось, т.к. зашел немного не с той стороны, но в итоге все равно добился желаемого.  Подмигивающий
« Последнее редактирование: Март 09, 2011, 15:37 от Eten » Записан
_govorilka
Гость
« Ответ #65 : Март 10, 2011, 08:25 »

Насчет id и name это вы правы, но для этого мне еще нужно воссоздать некоторое кол-во классов, чтобы постановка приобрела более четкую картину представления и ее можно было бы дать прочесть другим. Но на это потребуется не мало времени.

Код:
QHash<int, QString> idToName;
QHash<QString, int> nameToID;

В чем сложность?..
Записан
_govorilka
Гость
« Ответ #66 : Март 10, 2011, 08:32 »

Если в класс NDataTypes добавишь виртуальную функцию:

Код
C++ (Qt)
    QString toString() const = 0;
 

То вот этот кусок кода:

Код
C++ (Qt)
 
if (typeid(NNumeric) == typeid(*dt))
   {
       NNumeric numeric = *dynamic_cast<NNumeric*>(dt);
       str = QString(numeric);
   }
 
   if (typeid(NString) == typeid(*dt))
   {
       NString string = *dynamic_cast<NString*>(dt);
       str = string.value();
   }
 
   if (typeid(NLogical) == typeid(*dt))
   {
       NLogical logical = *dynamic_cast<NLogical*>(dt);
       str = QString(logical);
   }
 
 

Сможешь переписать так:

Код
C++ (Qt)
   QString str = dt->toString();
 
Записан
voral
Гость
« Ответ #67 : Март 10, 2011, 09:49 »

Не совсем по теме, но:
а) "this->" - так пишут на жабе, а здесь - ну можно, но если Вы хотите что-то подчеркнуть, а не просто так
Я то же так пишу. Цель: выделить то, что относится к классу от каких то "локальных" переменных. Можно сказать на всякий случай, что б потом если придется вернуться к коду через некий промежуток времени незадумываться
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


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

ИМХО, ненужное засорение кода.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #69 : Март 10, 2011, 11:00 »

А можете подсказать, в чем рыхловатость?
Ну вот например

if (typeid(NNumeric) == typeid(*dt))
    {
        NNumeric numeric = *dynamic_cast<NNumeric*>(dt);
        str = QString(numeric);
    }
 
    if (typeid(NString) == typeid(*dt))
    {
        NString string = *dynamic_cast<NString*>(dt);
        str = string.value();
    }

- зачем привлекать и typeid и еще dynamic_cast? Это вещи разные, здесь лучше обойтись одной,

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

- неясно зачем нужно возвращать numeric по значению, чем не устраивает просто указатель для получения строки?

- согласен с _govorilka что иметь метод типа toString гораздо проще/естественнее (может и обобщить удастся). Конструктор QString(numeric) не вызывается необходимостью

- если цель вернуть строку, то менять объекты мы не собираемся, значит это надо подчеркнуть словом const

Поэтому поприятнее так
Код
C++ (Qt)
const NNumeric * numeric = dynamic_cast<const NNumeric*> (dt);
if (numeric)
  str = numeric->toString();
else {
..
 
Или, как указал _govorilka , сделать toString методом базового класса тогда вместо ветвистого else всего одна проверка
Код
C++ (Qt)
const BaseClass * base = dynamic_cast<const BaseClass *> (dt); // возможно и это не нужно
if (base)
  str = base->toString();
 
Пусть не критично/обязательно, но в этом есть смысл.
Записан
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #70 : Март 10, 2011, 11:04 »

ИМХО, ненужное засорение кода.
Я тож так не пишу, но
Могу привести одну ситуацию, где так писать целесообразно:
Например у нас есть некоторый класс, который имеет закрытую переменную, назовём её value:
Код
C++ (Qt)
class A
{
public:
   void setValue(int value) { this->value = value; }
private:
   int value;
}
 
 
Однако у меня такое исключено, поскольку перед закрытыми переменными ставлю _
Записан

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

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

Сообщений: 2094



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

Или, как указал _govorilka , сделать toString методом базового класса тогда вместо ветвистого else всего одна проверка
Код
C++ (Qt)
const BaseClass * base = dynamic_cast<const BaseClass *> (dt); // возможно и это не нужно
if (base)
  str = base->toString();
 
Пусть не критично/обязательно, но в этом есть смысл.
Так даже более того, не нужно будет делать никакого приведения, поскольку toString() будет относится к интерфейсу.
Записан

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

Arch Linux Plasma 5
brankovic
Гость
« Ответ #72 : Март 10, 2011, 11:16 »

Однако у меня такое исключено, поскольку перед закрытыми переменными ставлю _

не рекомендуется стандартом, имена с _ и __ зараезервированы для стандартной библиотеки. Поля класса называю на m, типа m_name. Некоторые ставят _ в конце имени: name_. ИМХО любой способ лучше, чем this->.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #73 : Март 10, 2011, 12:02 »

Согласен с brankovic, ставлю после имени _. Перед именем не рекомендуют ставить _ из-за возможной коллизии имен с макросами.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #74 : Март 10, 2011, 12:26 »

пишу через d_ptr-_-
Записан
Страниц: 1 ... 3 4 [5] 6   Вверх
  Печать  
 
Перейти в:  


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