使用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" );
}
答案 0 :(得分:8)
如果label
超出范围,将调用析构函数(QLabel::~QLabel
)。来自docs:
销毁该对象,删除其所有子对象。
没有必要在堆上创建对象 - 您可以将对象放在堆栈上,但是您需要对对象的生命周期负责(关于在堆上分配数据的问题最大的问题之一是“谁和什么时候应该删除这些对象?”的问题,在Qt中它由层次结构处理 - 每当你删除你的小部件时,所有的子小部件都将被删除。)
为什么你的程序有效 - 我不知道 - 它可能不起作用(label
在范围的末尾被销毁)。另一个问题是 - 如果您没有引用它,您将如何更改label
的文本(例如,从某个插槽中)?
修改我刚看到您的label
是MainWindow
的成员。拥有一个完整的对象,而不是指向作为类成员的对象的指针是完全没问题的,因为在MainWindow
之前它不会被销毁。请注意,如果您创建MainWindow
的实例,请执行以下操作:
MainWindow *w = new MainWindow();
将在堆上创建 label
。
答案 1 :(得分:4)
因为这就是Qt的设计方式。我意识到这不是一个非常令人满意的答案,但是Qt被简单地设计为“在堆上创建小部件,父母负责删除他们的孩子”。
意识到Qt的起源比我们认为的“现代C ++”更古老,更早。
答案 2 :(得分:4)
要记住的另一件事是Qt使用所谓的pimpl范例,其中对象数据在您实际实例化的类后面隐式共享和管理。见这里:http://qt-project.org/wiki/Dpointer
最重要的是,如果你要在堆栈上进行分配以避免使用堆,那么Qt只是在你身上拉一个快速的并且无论如何都要使用堆。
答案 3 :(得分:3)
将窗口小部件分配为局部变量通常不是一个好主意,因为通常它会在以任何方式有用之前超出范围;因为QObject
通过其“父子关系”(与C ++析构函数很好地集成)支持组合模式,所以通常最简单的事情就是利用这样的特性。
另一方面,可以使其成为MainWindow
类的成员,或者通常以任何方式分配它,使其生命周期更少比其父母的生命周期。事实上,当这样的QLabel
被销毁时,它会自动从其父级注销,避免双重释放。但通常更方便的是将小部件分配到堆上,将它们注册为当前窗口的子级,因为通常在创建它们之后实际上不需要访问许多小部件(例如标签),因此不必杂乱你的班级有无用的数据成员。你只需要new QLabel(this, ...)
进入你的窗口构造函数就可以了。
不所做的是,如果他们的生命周期长于其父级的生命周期(例如将它们放在全局变量或静态变量中),则分配不带new
的小部件) - 执行此操作将导致父级尝试delete
它们的销毁,这将导致最坏的崩溃,最坏的情况下无声的内存损坏。这个可以修复(通过手动取消注册类析构函数中的小部件),但我无法想象任何这样的事情会有用的场景。
答案 4 :(得分:1)
主要原因 - 动态创建/删除小部件的可能性。 QObject(和QWidget)设计为无法复制构造函数的类,因此无法传递参数(通过值/引用)。因此,在所有情况下使用指针使代码更简单明了。