以下代码完美编译:
QObject* o = new QObject(0);
QWidget* w = new QWidget(0);
qobject_cast<QObject*>(w)->setParent(o);
我无法合法地将QObject
设为QWidget
的父级。但是使用qobject_cast
是可能的。是否有负面后果?
答案 0 :(得分:11)
强制QObject作为QWidget的父级有什么后果?
不可撤销的未定义行为。
Qt并非旨在支持QWidget
的非小部件父级。我认为这是Qt中的一个API错误,因为由于这种限制,QWidget
在Liskov替换原则意义上并不完全是QObject
。
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
来为父级浪费任何资源。