8

使用 C++ 和 Qt 创建 GUI 时,您可以创建一个标签,例如:

QLabel* label = new QLabel("Hey you!", centralWidgetParent);

这会在堆上创建对象并将一直留在那里,直到我手动删除它或父对象被销毁。我现在的问题是为什么我需要一个指针?为什么不在堆栈上创建它?

//Create a member variable of Class MainWindow
QLabel label;

//Set parent to show it and give a text so the user can see it
    QWidget* centralWidget = new QWidget(this); //Needed to add widgets to the window
    this->setCentralWidget( centralWidget ); 
    label.setParent(centralWidget);
    label.setText( "Haha" );

这很好用,我可以看到标签并且它没有消失。

我们在 C++ 中使用指针来让某些东西活得更久,这样我们就可以在各种范围内使用一个对象。但是当我创建一个成员变量时,它不会一直停留到对象被销毁吗?

编辑:也许我没有足够澄清。这是 MainWindow 类:

class MainWindow : public QMainWindow
{
    Q_OBJECT
    QLabel label; //First introduced here...

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
};

//Constructor
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QWidget* centralWidget = new QWidget(this);
    this->setCentralWidget( centralWidget );
    label.setParent(centralWidget);
    label.setText( "Haha" );
}
4

5 回答 5

8

如果您label超出范围,QLabel::~QLabel则将调用析构函数 ( )。从文档

销毁对象,删除其所有子对象。

没有必要在堆上创建对象 - 你可以将对象放在堆栈上,但是你需要对对象的生命周期负责(关于在堆上分配数据的最成问题的问题之一是“谁和什么时候应该删除这些对象?”,在 Qt 中它是由层次结构处理的——每当你删除你的小部件时,所有的子小部件都将被删除)。

为什么您的程序有效 - 我不知道 - 它可能无法正常工作(label在范围结束时被销毁)。label另一个问题是 -如果您没有对它的引用, 您将如何更改(例如从某个插槽)的文本?

编辑我刚刚看到您labelMainWindow. 拥有一个完整的对象是完全可以的,而不是将指向对象的指针作为类的成员,因为它之前不会被销毁MainWindow。请注意,如果您创建这样的实例MainWindow

MainWindow *w = new MainWindow();

label将在堆上创建。

于 2013-09-24T14:56:43.090 回答
6

因为这就是 Qt 的设计方式。我意识到这不是一个非常令人满意的答案,但 Qt 被简单地设计为“在堆上创建小部件,父母负责删除他们的孩子”。

意识到 Qt 的起源是古老的,比我们认为的“现代 C++”还要古老。

于 2013-09-24T14:56:19.630 回答
5

要记住的另一件事是,Qt 使用所谓的 pimpl 范例,其中对象数据在您实际实例化的类后面隐式共享和管理。见这里:http: //qt-project.org/wiki/Dpointer

底线是,如果您在堆栈上分配以避免使用堆,Qt 只是在您身上拉一个快速的并使用堆。

于 2013-09-24T19:11:16.043 回答
4

将小部件分配为局部变量通常不是一个好主意,因为通常它在以任何方式有用之前就会超出范围;由于QObject通过其“父子”关系(与 C++ 析构函数很好地集成)支持组合模式,通常最简单的事情就是利用这样的特性。

另一方面,您可以使其成为您的MainWindow类的成员,或者通常以任何方式分配它,使其生命周期小于其父级的生命周期。事实上,当此类QLabel被销毁时,它会自动从其父级注销,避免双重释放。但是通常只在堆上分配小部件,将它们注册为当前窗口的子窗口会更舒服,因为通常您在创建它们(例如标签)后实际上不需要访问许多小部件,因此没有必要混乱你的类有无用的数据成员。你只需new QLabel(this, ...)进入你的窗口构造函数,就是这样。

相反,你不应该的是分配你的小部件,如果它们的生命周期比它们的父级的生命周期长(例如将它们放在全局或静态变量中) - 这样做会导致父级在其销毁new时尝试它们delete,这充其量会导致崩溃,最坏的情况是静默内存损坏。这可以修复(通过手动取消注册类析构函数中的小部件),但我无法想象这样的事情会有用的任何场景。

于 2013-09-24T15:11:39.763 回答
1

主要原因 - 动态创建/删除小部件的可能性。QObject(和QWidget)设计为不能具有复制构造函数的类,因此您不能在参数中传递is(按值/引用)。因此,在所有情况下都使用指针可以使代码更加简单明了。

于 2013-09-24T15:52:50.413 回答