問題描述
以下代碼完美編譯:
QObject* o = new QObject(0);
QWidget* w = new QWidget(0);
qobject_cast<QObject*>(w)->setParent(o);
我不能合法地將 QObject
設置為 QWidget
的父級.但是使用 qobject_cast
是可能的.是否有負面影響?
I cannot legally set QObject
as a parent of QWidget
. But using qobject_cast
it is possible. Are there negative consequences?
推薦答案
強制 QObject 作為 QWidget 的父級有什么后果?
What are consequences of forcing QObject as a parent of QWidget?
不可撤銷的未定義行為.
Irrevocable undefined behavior.
Qt 并非旨在支持 QWidget
的非小部件父級.我認為這是 Qt 中的一個 API 錯誤,因為由于這種限制,QWidget
在 Liskov 替換原則意義上并不完全是 QObject
.
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 在嘗試激活小部件時會崩潰.所以它會一直工作,直到你專注于你的應用程序,然后會崩潰.
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 在 QObject::setParent()
中斷言.
Qt 5.x asserts in 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();
}
然后它會在其他地方崩潰.
It will crash somewhere else then.
您會在嘗試修補 Qt 以使其正常工作時進行一場艱苦的戰斗.我認為這不是一場值得的斗爭 - 除非決定使 QWidget
真正成為 QObject
并更改其構造函數簽名.這最早可以在 Qt 6 中完成,因為它是一個二進制不兼容的更改 AFAIK.
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.
此外,您嘗試做的事情大多是不必要的.您當然可以為多個獨立的頂級小部件設置一個隱藏的 QWidget
父級.
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();
}
隱藏小部件的開銷很小,您不會通過使用 QWidget
而不是 QObject
為父級浪費任何資源.
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.
這篇關于強制 QObject 作為 QWidget 的父級有什么后果?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!