gpt4 book ai didi

c++ - 堆栈与堆属性的 QT 特定差异?

转载 作者:行者123 更新时间:2023-11-30 02:29:07 27 4
gpt4 key购买 nike

通常,在编写 C++ 代码时,我会将对象始终保存为普通属性,从而利用 RAII。然而,在 QT 中,删除对象的责任在 QObject 的析构函数中。所以,假设我们定义了一些特定的小部件,那么我们有两种可能性:

1) 使用QT的系统

class Widget1 : QWidget
{
Q_OBJECT
public:
Widget1(QWidget* parent = nullptr);

private:
QPushButton* myButton; // create it with "new QPushButton(this);"
};

2)使用RAII

class Widget2 : public QWidget
{
Q_OBJECT
public:
Widget2(QWidget* parent = nullptr);

private:
QPushButton button; // normal RAII
};

通常,我使用第一种方法。如果父级不仅通过布局了解其子级,似乎某事 可以更好地工作。但是想想……真正的原因我不太清楚。

我知道堆栈是有限的。但是假设这在这里不起作用。毕竟,堆栈并不那么小。

最佳答案

It seems that something could work better if a parent knows its children not only by layout.

你是对的。 QObject 的父级不仅用于内存管理目的,this answer总结了它的一些其他用法。这里最重要的是 QWidget 的(因为您担心添加成员 QWidget),所以如果您按原样使用第二种方法编写它时,您可能会遇到一些问题:

  • 假设您正在实例化 Widget1 并将其显示在您的主函数中,如下所示:

    Widget1 w;
    w.show();

    这将显示一个空的小部件,其中没有按钮。与 buttonWidget1 对象的子对象时的行为相反,调用 show()显示小部件父级及其所有子级。

    使用 setEnabled() 时会发生类似的问题, setLayoutDirection() , ...

  • button.pos()不会返回相对于 Widget1 的坐标,实际上按钮甚至没有显示在其中。使用 move() 时同样的问题。

  • 事件系统可能无法按预期工作。因此,如果成员小部件不处理某些鼠标/键盘事件,该事件将不会传播到 小部件(因为没有指定父级)。

但是第二种方法可以写成利用与 RAII 的父关系,从而避免上述问题:

class Widget2 : public QWidget
{
public:
explicit Widget2(QWidget* parent = nullptr):QWidget(parent){}

private:
QPushButton button{this}; //C++11 member initializer list
};

或者,在 C++11 之前的版本中:

class Widget2 : public QWidget
{
public:
//initialize button in constructor, button's parent is set to this
explicit Widget2(QWidget* parent = Q_NULLPTR):QWidget(parent), button(this){}

private:
QPushButton button;
};

这样,两种方法之间的 Qt Framework 就没有任何区别。事实上,使用第二种方法避免了不必要的动态分配(请注意,如果在某些嵌套循环中非常频繁地执行分配,这可能会有稍微更好的性能。但是,对于大多数应用程序,性能在这里并不是真正的问题)。因此,您可能会像这样编写小部件:

class Widget : public QWidget
{
public:
explicit Widget(QWidget* parent = nullptr):QWidget(parent){
//add widgets to the layout
layout.addWidget(&button);
layout.addWidget(&lineEdit);
layout.addWidget(&label);
}
~Widget(){}

private:
//widget's layout as a child (this will set the layout on the widget)
QVBoxLayout layout{this};
//ui items, no need to set the parent here
//since this is done automatically in QLayout::addWidget calls in the constructor
QPushButton button{"click here"};
QLineEdit lineEdit;
QLabel label{"this is a sample widget"};
};

这很好,有人可能会说这些子部件/对象将被销毁两次,第一次是在它们超出范围时,第二次是在它们的父级被销毁时,这使得该方法不安全.这不是问题,因为一旦子对象被销毁,它就会将自己从其父对象的子对象列表中删除,参见docs .因此,每个对象都只会被销毁一次

关于c++ - 堆栈与堆属性的 QT 特定差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39931734/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com