c++ Qt:子对象可以在父对象中组合吗?

6fe3ivhb  于 2023-07-01  发布在  其他
关注(0)|答案(7)|浏览(99)

在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(但没有父级的widget不会变成顶级窗口吗?)
*,widget始终需要堆分配。

哪一个是正确的?

vaj7vani

vaj7vani1#

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

mcvgt66p

mcvgt66p2#

Object trees & ownership回答您的问题。基本上,当子对象在堆上创建时,它将被其父对象删除。
另一方面,当在堆栈上创建子对象时,析构的顺序很重要。子元素将在其父元素之前被销毁,并将自身从其父元素的列表中移除,这样它的析构函数就不会被调用两次。
在该链接中还有一个例子显示了有问题的销毁顺序。

f0brbegy

f0brbegy3#

文档中说,任何从QObject派生的对象在其父对象被销毁时都会自动销毁;这意味着调用delete
不。它意味着对该特定实体的析构函数的调用
比如在你的例子中,如果MyWindow被销毁,这意味着MyWindow的析构函数已经被调用。这反过来将调用析构函数myButton,该析构函数已经在QPushButton中实现。
如果你有一个复合实体,只有析构函数会被调用,而不是delete,所以它不会崩溃。
Qt中的父子关系并不特别要求在堆栈或堆中。它可以在任何东西。
这里有一个类似的例子,在堆栈上的父子关系。
HTH..

enxuqcxy

enxuqcxy4#

对象只有在有父指针时才会被销毁,所以你可以用途:

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

zysjyyx45#

你应该在堆上创建它,因为QObject会销毁它:

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

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

zkure5ic6#

调用delete操作符不会使你的应用程序崩溃,你可以阅读下面的引用
Qt的父子机制是在QObject中实现的。当我们创建一个带有父对象的对象(小部件、验证器或任何其他类型)时,父对象会将该对象添加到其子对象的列表中。删除父级时,它将遍历其子级列表并删除每个子级。然后,子节点自己删除所有子节点,依此类推,直到没有剩余的子节点。父子机制大大简化了内存管理,降低了内存泄漏的风险。唯一必须调用delete的对象是我们用new创建的没有父对象的对象。如果我们在父对象之前删除一个子对象,Qt将自动从父对象的子对象列表中删除该对象。
注意,父参数默认为NULL(默认参数),这是QPushButton构造函数

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

所以你可以使用

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

并且u可以在任何组件和任何时间调用delete
Qt会照顾这一点

jm81lzqq

jm81lzqq7#

让我在这里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 *。

相关问题