2015-03-11 1 views
5

Следующий код компилируется отлично:Каковы последствия принудительного QObject как родителя QWidget?

QObject* o = new QObject(0); 
QWidget* w = new QWidget(0); 
qobject_cast<QObject*>(w)->setParent(o); 

Я не могу законно установить QObject как родитель QWidget. Но использование qobject_cast возможно. Есть ли негативные последствия?

+1

Просто любопытно: в чем причина такой иерархии? – vahancho

+3

Что?!? QWidget наследуется публично из QObject –

+2

'QWidget :: setParent (QWidget *)' скрывает 'QObject :: setParent (QObject *)'. – Oktalist

ответ

9

Qt не предназначен для поддержки родителя без виджета QWidget. Лично я рассматривал бы это как бессмысленный хак на данный момент. Он будет компилироваться, но никогда не будет работать. Я считаю это ошибкой API в Qt, поскольку QWidget не является полностью QObject в смысле Принципа замены Лискова из-за этого ограничения.

Qt 4.x будет поврежден при попытке активации виджета. Так что это сработает, пока вы не сфокусируете свое приложение и не сработаете.

Qt 5.x утверждает в QObject::setParent().

утверждение можно обойти, хотя:

// https://github.com/KubaO/stackoverflown/tree/master/questions/widget-parent-28992276 
#include <QApplication> 
#include <QLabel> 

class ParentHacker : private QWidget { 
public: 
    static void setParent(QWidget * child_, QObject * parent) { 
     // The following line invokes undefined behavior 
     auto child = static_cast<ParentHacker*>(child_); 
     Q_ASSERT(child->d_ptr->isWidget); 
     child->d_ptr->isWidget = 0; 
     child->QObject::setParent(parent); 
     child->d_ptr->isWidget = 1; 
    } 
}; 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    QLabel w{"Hello!"}; 
    w.setMinimumSize(200, 100); 
    w.show(); 
    ParentHacker::setParent(&w, &app); 
    return app.exec(); 
} 

Это будет врезаться куда-нибудь потом.

Вы будете сражаться в гору, пытаясь исправить Qt, чтобы заставить его работать. Думаю, что это не достойный бой, если не принято решение сделать QWidget по-настоящему QObject и изменить его подпись конструктора. Это можно сделать как можно скорее в Qt 6, поскольку это двоично-несовместимое изменение AFAIK.

Более того, то, что вы пытаетесь сделать, в основном не нужно. У вас наверняка есть скрытый родитель QWidget для нескольких автономных виджетов верхнего уровня.

#include <QApplication> 
#include <QLabel> 

int main(int argc, char ** argv) { 
    QApplication app{argc, argv}; 
    QWidget parent; 
    QLabel l1{"Close me to quit!"}, l2{"Hello!"}; 
    for (auto label : {&l1, &l2}) { 
     label->setMinimumSize(200, 100); 
     label->setParent(&parent); 
     label->setWindowFlags(Qt::Window); 
     label->setText(QString("%1 Parent: %2."). 
        arg(label->text()).arg((quintptr)label->parent(), 0, 16)); 
     label->show(); 
    } 
    l2.setAttribute(Qt::WA_QuitOnClose, false); 
    return app.exec(); 
} 

Накладные иметь виджет скрытый минимален, вы не тратить любые ресурсы, используя QWidget вместо QObject для родителей.

Смежные вопросы