The following code compiles perfectly:
QObject* o = new QObject(0);
QWidget* w = new QWidget(0);
qobject_cast<QObject*>(w)->setParent(o);
I cannot legally set QObject
as a parent of QWidget
. But using qobject_cast
it is possible. Are there negative consequences?
What are consequences of forcing QObject as a parent of QWidget?
Irrevocable undefined behavior.
Qt is not designed to support a non-widget parent to a QWidget
. I consider it an API bug in Qt, since a QWidget
isn't fully a QObject
in the Liskov Substitution Principle sense because of that limitation.
Qt 4.x will crash when attempting to activate the widget. So it'll work until you focus your application and then will crash.
Qt 5.x asserts in QObject::setParent()
.
The assertion can be bypassed, though:
// 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();
}
It will crash somewhere else then.
You'd be fighting an uphill battle trying to patch Qt to get it to work. It's not a worthwhile fight, I think - not unless a decision is made to make a QWidget
truly-a QObject
and change its constructor signature. That can be done at the earliest in Qt 6 since it's a binary-incompatible change AFAIK.
Moreover, what you're trying to do is mostly unnecessary. You can certainly have a hidden QWidget
parent to multiple stand-alone top-level widgets.
#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();
}
The overhead of having the widget hidden is minimal, you're not wasting any resources by using a QWidget
instead of a QObject
for the parent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With