问:子对象可以在父对象中组合吗?

时间:2011-06-03 07:46:36

标签: c++ qt qwidget qobject

在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(但不会将无父级小部件变为顶级窗口?)
  • ,小部件总是必须进行堆分配。

哪一个是正确的?

7 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:4)

  

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

没有。它暗示调用该特定实体的析构函数

在您的示例中,如果MyWindow被销毁,则表示已调用MyWindow的析构函数。反过来,它将调用已在myButton中实现的析构函数QPushButton

如果你有复合实体,那么只会在该实体上调用析构函数而不是delete,因此它不会崩溃。

Qt中的父子关系不需要专门存在于堆栈或堆中。它可以是任何东西。

堆栈上父​​子关系中的类似示例超过here

HTH ..

答案 2 :(得分:4)

Object trees & ownership回答了您的问题。基本上,当在堆上创建子对象时,它将被其父对象删除。

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

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:0)

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

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

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

答案 5 :(得分: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会关注这一点

答案 6 :(得分:0)

让我在这里quote the source

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在析构函数中的每个子节点。此外,析构函数被执行before任何成员的析构函数;因此,如果所讨论的复合材料等于父级 - 那么成员QObject将没有任何机会将其自身从其父级的子列表中删除。

遗憾的是,这意味着您无法QObject撰写成其父。但是,只要您保证破坏对象或在父开始破坏之前将其父级重置为0 ,您就可以组成其他对象,以及在堆栈上进行分配。