14

在 Qt 中,我可以通过组合将子小部件嵌入到它们的父级中,还是必须使用new?

class MyWindow : public QMainWindow
{
    ...
private:
    QPushButton myButton;
}

MyWindow::MyWindow ()
 : mybutton("Do Something", this)
{
   ...
}

文档说,任何派生自的对象QObject都会在其父对象被销毁时自动销毁;这意味着调用delete,在上面的示例中会崩溃。

我必须使用以下内容吗?

QPushButton* myButton;

myButton = new QPushButton("Do Something", this);

编辑

答案是多种多样的,基本上可以归结为三种可能性:

  • 的,构图还可以。Qt 可以弄清楚对象是如何分配的,并且只有delete堆分配的对象(这是如何工作的?)
  • 的,组合是好的,但不要指定父级,因为父级否则会调用delete对象(但是没有父级的小部件不会变成顶级窗口吗?)
  • ,小部件总是必须在堆上分配。

哪一个是正确的?

4

7 回答 7

7

当特定对象的删除序列开始时,将删除非静态、非堆成员变量。只有当所有成员都被删除时,才会进入基类的析构函数。因此 QPushButton myButton 成员将在 ~QMainWindow() 被调用之前被删除。并且来自 QObject 文档:“如果我们在其父对象之前删除一个子对象,Qt 将自动从父对象的子对象列表中删除该对象”。因此不会发生崩溃。

于 2011-06-03T11:49:31.820 回答
4

文档说,任何从 QObject 派生的对象都会在其父对象被销毁时自动销毁;这意味着调用删除

不,这意味着调用该特定实体的析构函数。

在您的示例中说,如果MyWindow被销毁,则意味着MyWindow已调用了析构函数。这反过来又会调用myButton已经在QPushButton.

如果您有复合实体,则只会在该实体上调用析构函数,但不会调用它delete,因此它不会崩溃。

Qt 中的父子关系不需要特别位于堆栈或堆中。它可以在任何东西中。

堆栈上的父子关系中的类似示例在此处结束。

HTH..

于 2011-06-03T08:39:47.917 回答
4

对象树和所有权回答了您的问题。基本上,当在堆上创建子对象时,它将被其父对象删除。

另一方面,当在堆栈上创建子对象时,销毁顺序很重要。子级将在其父级之前被销毁,并将其从其父级列表中删除,以便其析构函数不会被调用两次。

该链接中还有一个示例显示了有问题的破坏顺序。

于 2011-06-03T11:49:01.243 回答
2

该对象仅在具有父指针时才会被销毁,因此您可以使用:

MyWindow::MyWindow ()
 : mybutton("Do Something", 0)
{
   ...
}
于 2011-06-03T07:56:29.193 回答
0

您应该在堆上创建它,因为 QObject 会破坏它:

class MyWindow : public QMainWindow
{
    ...
private:
    QPushButton *myButton;
}

MyWindow::MyWindow ()
 : mybutton( new QPushButton( "Do Something", this) )
{
   ...
}
于 2011-06-03T07:56:50.423 回答
0

调用delete运算符不会使您的应用程序崩溃,您可以阅读以下引用

Qt 的父子机制是在 QObject 中实现的。当我们使用父对象创建对象(小部件、验证器或任何其他类型)时,父对象会将对象添加到其子对象列表中。当父级被删除时,它会遍历其子级列表并删除每个子级。然后孩子们自己删除他们所有的孩子,以此类推,直到没有留下。父子机制极大地简化了内存管理,降低了内存泄漏的风险。我们必须调用 delete 的唯一对象是我们使用 new 创建且没有父对象的对象。如果我们在其父对象之前删除一个子对象,Qt 会自动从父对象的子对象列表中删除该对象。

请注意,默认情况下,父参数是NULL(默认参数)这是 QPushButton 构造函数

QPushButton ( const QString & text, QWidget * parent = 0 )

所以你可以使用

    MyWindow::MyWindow () : mybutton( new QPushButton( "Do Something") ){   ... }

你可以随时调用delete任何组件

Qt 会注意这一点

于 2011-06-03T08:17:10.270 回答
0

让我在这里引用来源

816 QObject::~QObject()
817 {
818     Q_D(QObject);
819     d->wasDeleted = true;
820     d->blockSig = 0; // unblock signals so we always emit destroyed()
821 
   ...
924 
925     if (!d->children.isEmpty())
926         d->deleteChildren();
927 
928     qt_removeObject(this);
929 
930     if (d->parent)        // remove it from parent object
931         d->setParent_helper(0);
932 
933 #ifdef QT_JAMBI_BUILD
934     if (d->inEventHandler) {
935         qWarning("QObject: Do not delete object, '%s', during its event handler!",
936                  objectName().isNull() ? "unnamed" : qPrintable(objectName()));
937     }
938 #endif
939 }

    ...

1897 void QObjectPrivate::deleteChildren()
1898 {
1899     const bool reallyWasDeleted = wasDeleted;
1900     wasDeleted = true;
1901     // delete children objects
1902     // don't use qDeleteAll as the destructor of the child might
1903     // delete siblings
1904     for (int i = 0; i < children.count(); ++i) {
1905         currentChildBeingDeleted = children.at(i);
1906         children[i] = 0;
1907         delete currentChildBeingDeleted;
1908     }
1909     children.clear();
1910     currentChildBeingDeleted = 0;
1911     wasDeleted = reallyWasDeleted;
1912 }

如您所见,它的每个子项QObject确实delete都在析构函数中。此外,析构函数在任何成员的析构函数之前执行;因此,如果所讨论的组合等于父级 - 那么成员QObject将没有任何机会将自己从其父级的子级列表中删除。

不幸的是,这意味着您不能将a 组合QObject它的 parent中。但是你可以组合成其他对象,也可以在堆栈上分配——只要你保证在父对象开始销毁之前销毁对象或将其父对象重置为 0。

于 2013-04-01T15:59:36.233 回答