【问题标题】:Why are QWidgets accessed by pointers?为什么 QWidgets 是通过指针访问的?
【发布时间】:2016-02-13 09:42:25
【问题描述】:

我是 Qt5 的新手,我正在学习 QWidgets 来开发应用程序。

我注意到在许多示例中,QWidget 几乎总是通过指针访问。例如:

#include <QApplication>
#include <QWidget>
#include <QFrame>
#include <QGridLayout>

class Cursors : public QWidget {

 public:
     Cursors(QWidget *parent = 0);
};

Cursors::Cursors(QWidget *parent)
    : QWidget(parent) {

  QFrame *frame1 = new QFrame(this);
  frame1->setFrameStyle(QFrame::Box);
  frame1->setCursor(Qt::SizeAllCursor);

  QFrame *frame2 = new QFrame(this);
  frame2->setFrameStyle(QFrame::Box);
  frame2->setCursor(Qt::WaitCursor);

  QFrame *frame3 = new QFrame(this);
  frame3->setFrameStyle(QFrame::Box);
  frame3->setCursor(Qt::PointingHandCursor);

  QGridLayout *grid = new QGridLayout(this);
  grid->addWidget(frame1, 0, 0);
  grid->addWidget(frame2, 0, 1);
  grid->addWidget(frame3, 0, 2);

  setLayout(grid);
}

int main(int argc, char *argv[]) {

  QApplication app(argc, argv);  

  Cursors window;

  window.resize(350, 150);
  window.setWindowTitle("Cursors");
  window.show();

  return app.exec();
}

这摘自教程:http://zetcode.com/gui/qt5/firstprograms/

然而,在同一页面上,我看到我们可以通过对象本身访问 QWidget 基类:

#include <QApplication>
#include <QWidget>

int main(int argc, char *argv[]) {

    QApplication app(argc, argv);

    QWidget window;

    window.resize(250, 150);
    window.setWindowTitle("Simple example");
    window.show();

    return app.exec();
}

为什么必须通过指针访问所有 QWidget 派生类?为什么不需要通过指针访问 QWidget 本身?

【问题讨论】:

  • 两者都不需要。在类方法中创建局部变量可能更容易,而不是声明一堆您只会访问一次的成员变量。而且由于您需要小部件在方法范围之外生存,因此您使用new 初始化它们。见object trees & ownership

标签: c++ qt pointers qtwidgets


【解决方案1】:

QClass 的大小更大,您不想通过在堆栈内存中实例化它们来填满堆栈内存。

当您实例化派生类对象时,它还运行基类(派生类+基类)的构造函数,需要内存,

另一方面,QWidget 只继承 QObject 和 QPaintDevice,如您所见here

因此在堆栈内存上创建 QWidget 对象的开销会更少。

在使用堆内存时一定要非常小心,请阅读memory management上的答案

可以从here研究栈和堆的区别

【讨论】:

  • 一个类可以有几个基于 QWidget 的对象的成员,这些成员不需要是指针并且它们仍然不会在堆栈上,只要 owning 对象是不在堆栈上。在这种情况下,基于 QWidget 的对象的成员和方法将无法通过指针访问。例如myApplication-&gt;frame1.setCursor(Qt::PointingHandCursor) 或在对象 myApplication 内将只是 frame1.setCursor(Qt::PointingHandCursor)
  • 在堆上创建对象的好习惯?这是一个相当广泛的说法。
  • 在堆上创建对象,在栈上创建它们的指针。例如 unique_ptr 或 shared_ptr
  • 但是对于短寿命的对象,除其他外,它是不必要的。
【解决方案2】:

这不是 QWidgets 特有的:它适用于每个 QObjects(Qt 基础基类,其他一切都派生自它)。

这是 Qt 框架的设计选择的结果。引用 Qt 文档:

QObject 既没有复制构造函数也没有赋值运算符。 这是设计使然。

[...]

主要的后果是你应该使用 指向 QObject (或您的 QObject 子类)的指针,您可能在其中 否则很想将您的 QObject 子类用作值。为了 例如,没有复制构造函数,就不能使用 QObject 作为要存储在容器类之一中的值。你 必须存储指针。

来源:

http://doc.qt.io/qt-5.5/qobject.html#no-copy-constructor

这里解释了这种选择的理由:

http://doc.qt.io/qt-5.5/object.html#identity-vs-value

【讨论】:

  • 另外一个用于实际链接到有关该主题的文档。
【解决方案3】:

这一切都与对象的生命周期和共享所有权有关。如果你在函数中的堆栈上创建一个对象,它会在作用域结束时被销毁。

在您的示例中,为什么不需要通过指针访问 QWidget?只是因为当 main() '结束'时,你的程序就结束了,小部件可能会被销毁。

为什么需要通过指针访问 QWidget 的孩子?因为如果你想要求 QWidget 让你访问它的孩子,它不能给你一个值,因为它只是一个对象的副本。此外,如果你将一个大对象按值传递给 QWidget,它需要复制你的对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-13
    • 2019-11-26
    相关资源
    最近更新 更多