强制QObject作为QWidget的父级有什么后果?

rmf*_*low 8 c++ qt

以下代码完美编译:

QObject* o = new QObject(0);
QWidget* w = new QWidget(0);
qobject_cast<QObject*>(w)->setParent(o);
Run Code Online (Sandbox Code Playgroud)

我不能合法地设定QObject为父母QWidget.但使用qobject_cast它是可能的.有负面后果吗?

Rei*_*ica 12

强制QObject作为QWidget的父级有什么后果?

不可撤销的未定义行为.

Qt不是为支持非小部件父级而设计的QWidget.我认为这是Qt中的API错误,因为由于这种限制,QWidgeta QObject在Liskov Substitution Principle意义上并不完全是一个.

尝试激活小部件时,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();
}
Run Code Online (Sandbox Code Playgroud)

它会在其他地方崩溃.

你正在努力拼抢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();
}
Run Code Online (Sandbox Code Playgroud)

隐藏窗口小部件的开销很小,您不会通过使用QWidget而不是QObject为父窗口来浪费任何资源.