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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: qpolymorphic_downcast  (Прочитано 7534 раз)
Akon
Гость
« : Сентябрь 08, 2010, 22:04 »

Аналог boost::polymorphic_downcast<>() для QObject типов. Над boost::polymorphic_downcast<>() имеет те же преимущества/недостатки, что и qobject_cast<>() над dynamic_cast<>() (см. Ассистант). 

Код:
/// Convenient type conversions under QObject classes with RTTI-independent qobject_cast<>().
/// Acts like boost::polymorphic_downcast<>().
/// Usage example:
/// \code
/// QObjectDerived* derived = qpolymorphic_downcast<QObjectDerived*>(ptr);
/// \endcode
template <typename T>
T qpolymorphic_downcast(QObject* obj)
{
Q_ASSERT(qobject_cast<T>(obj));
return static_cast<T>(obj);
}
template <typename T>
T qpolymorphic_downcast(const QObject* obj)
{
return qpolymorphic_downcast<T>(const_cast<QObject*>(obj));
}
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3260


Просмотр профиля
« Ответ #1 : Сентябрь 08, 2010, 22:44 »

а чем не угодил сам куобжект каст?
Записан
lit-uriy
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3880


Просмотр профиля WWW
« Ответ #2 : Сентябрь 08, 2010, 23:42 »

вроде как применяться должно так:
Код
C++ (Qt)
Type *t = polymorphic_downcast<Type>(obj)

Хотя внутренности говорят, что написать можно было и так:
Код
C++ (Qt)
Type *t = static_cast<Type>(obj)
что явно короче.

Тогда в чём выгода?
Записан

Юра.
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #3 : Сентябрь 08, 2010, 23:45 »

а чем не угодил сам куобжект каст?
Насколько я понял, нет оверхеда в релизе, а при отладке работает проверка на корректность. Хотя пользоваться надо с осторожностью..
Записан

Гугль в помощь
Rcus
Гость
« Ответ #4 : Сентябрь 09, 2010, 05:20 »

Похоже не я один такой (http://www.prog.org.ru/index.php?topic=12932.msg83293#msg83293). Правда в текущей версии я слегка модифицировал код:
Код
C++ (Qt)
template<class T> inline T rzobject_cast(QObject *o)
{
#ifdef QT_DEBUG
   if (!qobject_cast<T>(o)) {
       if (!o) {
           qFatal("rzobject_cast failed cause arg=NULL");
       } else {
           T target_obj;
           qFatal("rzobject_cast failed: got object '%s' class '%s' instead of '%s'",
                   qPrintable(o->objectName()), o->metaObject()->className(),
                   target_obj->staticMetaObject.className());
       }
       Q_ASSERT(!"rzobject_cast fail");
   }
#endif
   return static_cast<T>(o);
}
 
Записан
Akon
Гость
« Ответ #5 : Сентябрь 09, 2010, 10:32 »

вроде как применяться должно так:
Код
C++ (Qt)
Type *t = polymorphic_downcast<Type>(obj)

Хотя внутренности говорят, что написать можно было и так:
Код
C++ (Qt)
Type *t = static_cast<Type>(obj)
что явно короче.

Тогда в чём выгода?


Из boost:

The C++ built-in static_cast can be used for efficiently downcasting pointers to polymorphic objects, but provides no error detection for the case where the pointer being cast actually points to the wrong derived class. The polymorphic_downcast template retains the efficiency of static_cast for non-debug compilations, but for debug compilations adds safety via an assert() that a dynamic_cast succeeds.

The C++ built-in dynamic_cast can be used for downcasts and crosscasts of pointers to polymorphic objects, but error notification in the form of a returned value of 0 is inconvenient to test, or worse yet, easy to forget to test. The throwing form of dynamic_cast, which works on references, can be used on pointers through the ugly expression &dynamic_cast<T&>(*p), which causes undefined behavior if p is 0. The polymorphic_cast template performs a dynamic_cast on a pointer, and throws an exception if the dynamic_cast returns 0.

polymorphic_downcast example:

#include <boost/cast.hpp>
...
class Fruit { public: virtual ~Fruit(){}; ... };
class Banana : public Fruit { ... };
...
void f( Fruit * fruit ) {
// ... logic which leads us to believe it is a Banana
  Banana * banana = boost::polymorphic_downcast<Banana*>(fruit);
  ...

Описанное решение предлагает ту же семантику, но реализовано посредством не C++-шного dynamic_cast<>(), а Qt-шного qobject_cast<>(). Чем в данном случае qobject_cast<>() лучше/хуже dynamic_cast<>() см. Ассистант.

Похоже не я один такой (http://www.prog.org.ru/index.php?topic=12932.msg83293#msg83293). Правда в текущей версии я слегка модифицировал код:
Код
C++ (Qt)
template<class T> inline T rzobject_cast(QObject *o)
{
#ifdef QT_DEBUG
   if (!qobject_cast<T>(o)) {
       if (!o) {
           qFatal("rzobject_cast failed cause arg=NULL");
       } else {
           T target_obj;
           qFatal("rzobject_cast failed: got object '%s' class '%s' instead of '%s'",
                   qPrintable(o->objectName()), o->metaObject()->className(),
                   target_obj->staticMetaObject.className());
       }
       Q_ASSERT(!"rzobject_cast fail");
   }
#endif
   return static_cast<T>(o);
}
 


Твое решение более информативно в плане сообщений; ничего не имею против, но мне достаточно останова по ассерту с последующим восхождением по стеку в отладчике для локализации ошибки. Все равно эти сообщения не для пользователя, а для программиста.

Код:
T target_obj;
- создаешь временный объект + тип Т должен быть default constructible, что снижает быстродействие и значительно сужает область применения. Вместо target_obj->staticMetaObject.className() пиши QObject::staticMetaObject.className(); target_obj тут не нужен. 
Записан
Rcus
Гость
« Ответ #6 : Сентябрь 09, 2010, 11:21 »

Твое решение более информативно в плане сообщений; ничего не имею против, но мне достаточно останова по ассерту с последующим восхождением по стеку в отладчике для локализации ошибки. Все равно эти сообщения не для пользователя, а для программиста.
У меня это тоже не для пользователя, только с 64M памяти отладчик не позапускаешь, да и корки писать некуда.

Код:
T target_obj;
- создаешь временный объект + тип Т должен быть default constructible, что снижает быстродействие и значительно сужает область применения. Вместо target_obj->staticMetaObject.className() пиши QObject::staticMetaObject.className(); target_obj тут не нужен. 
Моя реализация повторяет по записи остальные касты - указатели к указателям. Временный объект не создается, а этот dummy-pointer нужен для обращения к staticMetaObject нужного класса, QObject::staticMetaObject - не вариант.
Записан
Akon
Гость
« Ответ #7 : Сентябрь 09, 2010, 13:22 »

Моя реализация повторяет по записи остальные касты - указатели к указателям. Временный объект не создается, а этот dummy-pointer нужен для обращения к staticMetaObject нужного класса, QObject::staticMetaObject - не вариант.

Прошу прощения, я тут конкретно ошибся, потому как забыл, что аргументом шаблона будет указатель на тип а не сам тип. Соответственно:
1. Никакого временного объекта.
2. Вместо QObject::staticMetaObject конечно же нужно было T::staticMetaObject, но это не скомпилируется, т.к. T - указатель. Тут попрет boost::remove_pointer<T>::type::staticMetaObject.className(), но при наличии простого способа через dummy-pointer это выглядит извратом.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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