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

发布于 2024-11-13 07:37:03 字数 780 浏览 7 评论 0原文

在 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(但是无父级窗口小部件不会变成顶级窗口吗?)
  • ,窗口小部件始终必须是堆分配的。

哪一个是正确的?

In Qt, can I embed child widgets in their parent via composition, or do I have to create them with new?

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

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

The documentation says that any object derived from QObject will automatically destroyed when its parent is destroyed; this implies a call to delete, whcih in the above example would crash.

Do I have to use the following?

QPushButton* myButton;

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

EDIT

The answers are quite diverse, and basically boil down to three possibilities:

  • Yes, composition is ok. Qt can figure out how the object was allocated and only delete heap-allocated objects (How does this work?)
  • Yes, composition is ok, but don't specify a parent, since the parent would otherwise call delete on the object (But won't a parent-less widget turn into a top-level window?)
  • No, widgets always have to be heap-allocated.

Which one is correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

左耳近心 2024-11-20 07:37:03

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

The non-static, non-heap member variables are deleted when that particular object's delete sequence starts. Only when all members are deleted, will it go to the destructor of the base class. Hence QPushButton myButton member will be deleted before ~QMainWindow() is called. And from QObject documentation: "If we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children". Hence no crash will occur.

Bonjour°[大白 2024-11-20 07:37:03

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

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

该链接中还有一个示例,显示了有问题的销毁顺序。

Object trees & ownership answers your question. Basically when the child object is created on the heap it will be deleted by its parent.

On the other hand when the child object is created on the stack the order of destruction is important. The child will be destroyed before its parent and will remove itself from its parent's list so that its destructor is not called twice.

There is also an example in that link that shows problematic order of destruction.

司马昭之心 2024-11-20 07:37:03

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

否。它意味着调用该特定实体的析构函数

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

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

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

堆栈上父子关系的类似示例是 这里

哈..

The documentation says that any object derived from QObject will automatically destroyed when its parent is destroyed; this implies a call to delete

No. It implies a call to the destructor of that particular entity.

Say in your example, if MyWindow is destroyed, it means the destructor of the MyWindow has been called. Which in turn will call the destructor myButton which is implemented already in QPushButton.

If you have composite entity, just the destructor will be called on that entity but not delete and so it won't crash.

Parent child relationships in Qt doesn't require specifically to be in a stack or heap. It can be in anything.

A similar example in parent child relationship over a stack is over here.

HTH..

素罗衫 2024-11-20 07:37:03

该对象只有当它有父指针时才会被销毁,所以你可以使用:

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

The object will be destroyed only when it has a parent pointer, so you can use:

MyWindow::MyWindow ()
 : mybutton("Do Something", 0)
{
   ...
}
凉城 2024-11-20 07:37:03

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

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

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

You should create it on heap, since QObject will destroy it :

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

MyWindow::MyWindow ()
 : mybutton( new QPushButton( "Do Something", this) )
{
   ...
}
终止放荡 2024-11-20 07:37:03

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

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

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

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

因此您可以使用

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

并且可以在任何组件上调用 delete ,并且

Qt 会随时处理这一点

calling delete operator will not crash ur application, you can read the following quote

Qt's parent–child mechanism is implemented in QObject. When we create an object (a widget, validator, or any other kind) with a parent, the parent adds the object to the list of its children. When the parent is deleted, it walks through its list of children and deletes each child. The children themselves then delete all of their children, and so on recursively until none remain. The parent–child mechanism greatly simplifies memory management, reducing the risk of memory leaks. The only objects we must call delete on are the objects we create with new and that have no parent. And if we delete a child object before its parent, Qt will automatically remove that object from the parent's list of children.

note that the parent argument is NULL by default (default argument)
this is QPushButton Constructor

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

so u can use

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

and u can call delete on any component and any time

Qt will take care for this point

会傲 2024-11-20 07:37:03

让我在这里引用来源

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

不幸的是,这意味着您无法QObject组合到其父级中。但是您可以组合成其他对象,也可以在堆栈上分配 - 只要您保证在父对象开始破坏之前将其父对象重置为 0 即可。

Let me just quote the source here.

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 }

So as you can see, QObject does indeed delete each of its children in the destructor. In addition, the destructor is executed before destructors of any members; so if the composite in question equals the parent – then member QObject won't have any chance to remove itself from the children list of its parent.

This, unfortunately, means that you cannot compose a QObject into its parent. But you can compose into other objects, as well as allocate on stack – as soon as you guarantee to destruct the object or reset its parent to 0 before the parent starts destructing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文