Russian Qt Forum

Qt => Общие вопросы => Тема начата: pakulo от Май 13, 2007, 20:32



Название: Приведение типов
Отправлено: pakulo от Май 13, 2007, 20:32
Какая разница между
QWidget *widget = qobject_cast<QWidget *>(objectSender);

и
QWidget *widget = (QWidget *)(objectSender);


Название: Приведение типов
Отправлено: Alex Forth от Май 13, 2007, 20:50
Первый использует метаобьектную ситему Qt и возвратит 0, если преобразование невозможно, а второй просто позволяет преобразовать что-то размером в 4 байта(на х86) к типу QWidget *.


Название: Приведение типов
Отправлено: pakulo от Май 13, 2007, 21:58
Первым способом я могу преобразовать если создал свой виджет?

добавлено спустя 31 минуту:

 у меня есть клас
class MyLabel: public QLabel
{
}

делаю
MyLabel *lb;
QLabel *label = qobject_cast<QLabel *>(lb);

как мне получить 0?


Название: Приведение типов
Отправлено: Lion от Май 13, 2007, 22:18
Если Mylasbel не наследник QLabel, то получишь ноль.


Название: Приведение типов
Отправлено: pakulo от Май 13, 2007, 22:41
Ну это понятно... меня интересует как получить 0 если он наследник, см. мой пример...


Название: Приведение типов
Отправлено: QCasper от Май 13, 2007, 23:06
Цитата: "pakulo"
Ну это понятно... меня интересует как получить 0 если он наследник, см. мой пример...


Если lb == 0 то и label тоже будет 0.


Название: Приведение типов
Отправлено: Racheengel от Май 13, 2007, 23:33
MyLabel *lb;
QLabel *label = !(qobject_cast<QLabel *>(lb));

?


Название: Приведение типов
Отправлено: pakulo от Май 13, 2007, 23:44
Просто вот такая проблема
у меня есть два обьекта
MyLabel *lb;
QLabel *label;

в функцию передается QObject *
и мне в функции нужно проверить если это MyLabel сделать то-то, если QLabel те-то...


Название: Приведение типов
Отправлено: pastor от Май 13, 2007, 23:55
Цитата: "pakulo"
Просто вот такая проблема
у меня есть два обьекта
MyLabel *lb;
QLabel *label;

в функцию передается QObject *
и мне в функции нужно проверить если это MyLabel сделать то-то, если QLabel те-то...


Можно заюзать например такое:

Код:
...
QString name(obj->metaObject()->className());

if ( name == "MyLabel" ) {
    <do_something>
    return;
}

if ( name == "QLabel" ) {
    <do_something_else>
    return;
}
...


Название: Приведение типов
Отправлено: Tonal от Май 14, 2007, 08:29
Цитата: "pakulo"
Просто вот такая проблема
у меня есть два обьекта
MyLabel *lb;
QLabel *label;

в функцию передается QObject *
и мне в функции нужно проверить если это MyLabel сделать то-то, если QLabel те-то...

Именно для таких случаев в С++ существует dynamic_cast.
Он работает для классов у которых есть хотя бы одна виртуальная функция и только при включенном rtti.
В Qt ты можешь воспользоваться qobject_cast - это то же самое, что и стандартный dynamic_cast, но можно не включать rtti - Qt его эмулирует самостоятельно. qobject_cast работает только для наследников QObject, и  макрос Q_OBJECT должен быть. Иначе никто не гарантирует, что он вернёт. ;-)

P.S. Я предпочитаю использовать dynamic_cast как более универсальное средство. ;-)


Название: Приведение типов
Отправлено: Racheengel от Май 14, 2007, 08:44
Тогда наверно так:

MyLabel *lb;
QLabel *label = dynamic_cast<MyLabel *>(lb);

label будет = 0, если lb не объект класса MyLabel.


Название: Приведение типов
Отправлено: vregess от Май 19, 2007, 11:45
Информацию об объекте типа получают с помощью оператора typeid (нужно прицепить заголовок <typeinfo>).

Код:

 typeid(_MY_OBJECT_)

Здесь возвращается ссылка на объект типа type_info, который описывает тип объекта _MY_OBJECT_

Вторая форма:
Код:

 typeid(ИМЯ_ТИПА)

Ну тут понятно - type_info описывает тип ИМЯ_ТИПА. Эту форму можно использовать в инструкциях
сравнения типов.

(QWidget *)(objectSender) - это в Си. В С++ нужно использовать (по стандарту) различные *_cast.

Цитата: "pakulo"
Просто вот такая проблема
у меня есть два обьекта
MyLabel *lb;
QLabel *label;

в функцию передается QObject *
и мне в функции нужно проверить если это MyLabel сделать то-то, если QLabel те-то...



Код:

#include<typeinfo>
...
MyLabel *lb;
QLabel *label;
...
void BlaClass::doIt(QObject *o)
{
 if(typeid(o)==typeid(QLabel)){
   // do something
 }
 else if(typeid(o)==typeid(MyLabel)){
   // do something
 }
 else{
 // what a fuck?!
 }
}

Сам не проверял, но должно работать).
Вроде так. Если я ошибаюсь, было бы интересно услышать - где.


Название: Приведение типов
Отправлено: SABROG от Май 19, 2007, 12:13
А еще можно зарегистрировать свой MetaType:

Код:

Q_DECLARE_METATYPE(MyType)
struct MyType
{
    int id;
    QString str;
};
qRegisterMetaType<MyType>("MyType");
QVariant var = index.data(Qt::UserRole);
if ( var.canConvert<MyType>() )
{
MyType mt = var.value<MyType>();
model->setData(index, QVariant(qVariantFromValue(mt)), Qt::UserRole);
}
else ...


Название: Приведение типов
Отправлено: kitov от Май 19, 2007, 13:00
Цитата: "Tonal"
Цитата: "pakulo"
Просто вот такая проблема
у меня есть два обьекта
MyLabel *lb;
QLabel *label;

в функцию передается QObject *
и мне в функции нужно проверить если это MyLabel сделать то-то, если QLabel те-то...

Именно для таких случаев в С++ существует dynamic_cast.
Он работает для классов у которых есть хотя бы одна виртуальная функция и только при включенном rtti.
В Qt ты можешь воспользоваться qobject_cast - это то же самое, что и стандартный dynamic_cast, но можно не включать rtti - Qt его эмулирует самостоятельно. qobject_cast работает только для наследников QObject, и  макрос Q_OBJECT должен быть. Иначе никто не гарантирует, что он вернёт. ;-)

P.S. Я предпочитаю использовать dynamic_cast как более универсальное средство. ;-)


Для классов унаследованныx от QObject я бы предпочел
qobject_cast - быстрее ( ибо без rtti)


Название: Приведение типов
Отправлено: Tonal от Май 21, 2007, 10:10
Цитата: "kitov"
Для классов унаследованныx от QObject я бы предпочел
qobject_cast - быстрее ( ибо без rtti)
Есть реальные цифры?
На основании чего делается вывод, о тормознутости dynamic_cast по сравнению с qobject_cast


Название: Приведение типов
Отправлено: goer от Май 21, 2007, 11:29
Assitant:

Цитировать
The qobject_cast() function behaves similarly to the standard C++ dynamic_cast(), with the advantages that it doesn't require RTTI support and it works across dynamic library boundaries.
qobject_cast() can also be used in conjunction with interfaces;



Поскольку qobject_cast работает только для QObject-ов было бы глупо невоспользовоться этим ограничением для оптимизации кастинга ;)


Название: Приведение типов
Отправлено: kitov от Май 21, 2007, 14:42
Цитата: "Tonal"
Цитата: "kitov"
Для классов унаследованныx от QObject я бы предпочел
qobject_cast - быстрее ( ибо без rtti)
Есть реальные цифры?
На основании чего делается вывод, о тормознутости dynamic_cast по сравнению с qobject_cast


Какие тебе цифры надо ?
Напиши сам тест и замерь.
Всем исвестно что использование rtti
программу шустрее не делает.


Название: Приведение типов
Отправлено: goer от Май 21, 2007, 15:02
Да, узкое место в rtti это сравнение строк, если троли пошли не таким прямым путем, следует ожидать большей скорости.

Вобще мне тоже было бы интересно посмотреть на результаты тестов. ;)


Название: Приведение типов
Отправлено: Tonal от Май 22, 2007, 07:51
Открываем любой moc_*.cpp файл и внимательно рассматриваем функцию ClassName::qt_metacast(const char *_clname).
Сравнение строк и рекурсивные вызовы:
Код:

static const char qt_meta_stringdata_frmNotation[] = {
  "frmNotation\0"
};

void *frmNotation::qt_metacast(const char *_clname)
{
  if (!_clname) return 0;
  if (!strcmp(_clname, qt_meta_stringdata_frmNotation))
    return static_cast<void*>(const_cast< frmNotation*>(this));
  if (!strcmp(_clname, "Ui::frmNotation"))
    return static_cast< Ui::frmNotation*>(const_cast< frmNotation*>(this));
  return QDialog::qt_metacast(_clname);
}

Тут заметна ещё и потенциальная грабля с динамической линковкой при одноимённых классах в разных dll-ках.
Хотя эта задачку в рамках С++ автоматом пока не решается.

Про RTTI vs moc - компилятор знает всю иерархию класса, а moc - только непосредственных предков. Соответственно, умный компилятор, может сгенерировать довольно быструю функцию каста, чего moc не может в принципе.
Правда я не уверен, что какой-нибудь из компиляторов это делает. ;-)

Ну а тесты пусть делает тот, кто любит голословные утверждения на основе "общеизвестных фактов". ;-)


Название: Приведение типов
Отправлено: goer от Май 22, 2007, 09:27
Продуктивно поспорили. Одни говорят что черное чернее белого потому что это черное, а другие что белое белее черного потому что это белое ;)

Цитировать
Ну а тесты пусть делает тот, кто любит голословные утверждения на основе "общеизвестных фактов".


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


Название: Re: Приведение типов
Отправлено: Waryable от Октябрь 12, 2009, 05:05
Всем привет. Что бы не создавать тему-дубликат пишу здесь, тем более, что вопрос 100% подходит данной теме.
Вобщем, есть проблема: имеется набор классов-наследников от QObject. Эти классы категорически желательно пихнуть в контейнер. Я так подозреваю проблема решается через касты. Как говорится, я с "детства" не люблю приведение типов, и максимум на что решался - это приведение базовых типов. А вот теперь мне похоже никуда не деца.
Очень приветствуются не конкретные решения, а некие наставнические советы + ссылки на подробные материалы по кастам. Пошарил в нете, что-то не нашел подходящего материала. А хочется разобраться изнутри как это происходит.

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

И, всетаки, может кто производил спортивные соревнования на скорость м/у средствами Qt и С++?

ПС: Просьба сильно палками не бить.  ::)


Название: Re: Приведение типов
Отправлено: Waryable от Октябрь 12, 2009, 06:47
Пока не нашел нормального источника информации попробовал примерчик:

Код
C++ (Qt)
class myClass1   {}
class myClass2   {}
...
class myClassN   {}
 
 
myClass1* myCl1 = new myClass1;
myClass2* myCl2 = new myClass2;
...
myClassN* myClN = new myClassN;
 
QList<QObject*> myObjList;
 
myObjList.append(myCl1);
myObjList.append(myCl2);
...
myObjList.append(myClN);
 
myClass1* fromListCl = qobject_cast<myClass1*>(myObjList.at(0));
Дальнейшая работа с указателем fromListCl вроде бы корректна. Вызываю методы, изменяю данные. Но ведь не всегда видать сразу все грабли, на то они и грабли.


Название: Re: Приведение типов
Отправлено: kuzulis от Октябрь 12, 2009, 08:19
А точно нужно в:
Цитировать
myClass1* fromListCl = qobject_cast<myClass1*>(myObjList.at(1));

нужно myObjList.at(1) ??? Может надо  myObjList.at(0) ? :)


Название: Re: Приведение типов
Отправлено: Waryable от Октябрь 12, 2009, 08:57
А точно нужно в:
Цитировать
myClass1* fromListCl = qobject_cast<myClass1*>(myObjList.at(1));

нужно myObjList.at(1) ??? Может надо   myObjList.at(0) ? :)
Пардон, виноват не я, а копипаст зараза  :D
Исправил.


Название: Re: Приведение типов
Отправлено: pastor от Октябрь 12, 2009, 11:14
Так в чем собственно вопрос\проблема?


Название: Re: Приведение типов
Отправлено: Igors от Октябрь 12, 2009, 19:05
Я тоже проблемы не разглядел. Ну сделали MyBaseClass, у него virtual'ы, потом породили MyClass1, MyClass2 и.т.п, для них переопределили virtual'ы. Указатели поместили в контейнер и работаете типа

container[index]->MyVitualFunc(..);

Ну когда-то может придется тип узнать но с нормальным набором virtual'ов - редко.


Название: Re: Приведение типов
Отправлено: Waryable от Октябрь 14, 2009, 04:59
Спс всем кто отозвался.
Igors, я думал над этим вариантом. Но почему-то интуитивно его отбросил, наверное я был не прав. А поступил так из соображений эффективности, т.е. посчитал что приведение указателя в типу будет быстрее, чем неявный анализ информации о типе объекта. Но чуть въехав в тему я понял, что для приведения к типу необходимо производить свой анализ.
Так в чем собственно вопрос\проблема?
Ну вопроса было два:
1. насколько быстро производится приведение к типу.
2. надежность способа, который я привел выше.


Название: Re: Приведение типов
Отправлено: Igors от Октябрь 14, 2009, 11:14
А поступил так из соображений эффективности, т.е. посчитал что приведение указателя в типу будет быстрее, чем неявный анализ информации о типе объекта.
Не бывает просто "быстро/медленно" всегда что-то меряется по отношению к чему-то. Например, Вы собираетесь использовать QList. Операции с ним быстрые (если говорить "вообще") но намного медленнее чем приведение типов. Отказ от виртуальных методов не выигрывает в скорости если все равно находить тип вручную. 

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

Если есть какие-то сомнения в скорости приведения - возьмите это на себя. Псевдокод

Код:
class MyBaseTypedObject : public QObject {
  ...
  virtual int GetTypeId( void  ) const = 0;
};

Чтобы использовать switch вместо неприятной последовательности qobject_case

Код:
switch (obj->GetTypeId()) {
  case OBJ_TYPE_1:
    ((MyObj1 *) obj)->DoSomething();
    break;
   ...
}
Пусть оно сильно не поможет но "сердце успокоится" :)