Russian Qt Forum

Qt => Кладовая готовых решений => Тема начата: Akon от Сентябрь 08, 2010, 22:04



Название: qpolymorphic_downcast
Отправлено: 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));
}


Название: Re: qpolymorphic_downcast
Отправлено: Авварон от Сентябрь 08, 2010, 22:44
а чем не угодил сам куобжект каст?


Название: Re: qpolymorphic_downcast
Отправлено: lit-uriy от Сентябрь 08, 2010, 23:42
вроде как применяться должно так:
Код
C++ (Qt)
Type *t = polymorphic_downcast<Type>(obj)

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

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


Название: Re: qpolymorphic_downcast
Отправлено: navrocky от Сентябрь 08, 2010, 23:45
а чем не угодил сам куобжект каст?
Насколько я понял, нет оверхеда в релизе, а при отладке работает проверка на корректность. Хотя пользоваться надо с осторожностью..


Название: Re: qpolymorphic_downcast
Отправлено: Rcus от Сентябрь 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);
}
 


Название: Re: qpolymorphic_downcast
Отправлено: Akon от Сентябрь 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 тут не нужен. 


Название: Re: qpolymorphic_downcast
Отправлено: Rcus от Сентябрь 09, 2010, 11:21
Твое решение более информативно в плане сообщений; ничего не имею против, но мне достаточно останова по ассерту с последующим восхождением по стеку в отладчике для локализации ошибки. Все равно эти сообщения не для пользователя, а для программиста.
У меня это тоже не для пользователя, только с 64M памяти отладчик не позапускаешь, да и корки писать некуда.

Код:
T target_obj;
- создаешь временный объект + тип Т должен быть default constructible, что снижает быстродействие и значительно сужает область применения. Вместо target_obj->staticMetaObject.className() пиши QObject::staticMetaObject.className(); target_obj тут не нужен. 
Моя реализация повторяет по записи остальные касты - указатели к указателям. Временный объект не создается, а этот dummy-pointer нужен для обращения к staticMetaObject нужного класса, QObject::staticMetaObject - не вариант.


Название: Re: qpolymorphic_downcast
Отправлено: Akon от Сентябрь 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 это выглядит извратом.