什么是更好的?如果孩子是班级成员,是否为孩子设置QObject父母?

时间:2015-10-20 13:39:15

标签: c++ qt

class A : public QObject {
  A() : b(this) {} // !


  class B : public QObject {
    B(QObject* parent)
  };
  B b;
}

如果子对象不是动态的,我应该设置父级吗?这两种情况有什么区别?

什么更好,有什么区别?

class A : public QObject {
  A() : b(new B(this)) {} // !


  class B : public QObject {
    B(QObject* parent)
  };
  B* b;
}

class A : public QObject {
  A() : b(new B()) {} // !


  class B : public QObject {
    B()
  };
  smart_ptr<B> b;
}

2 个答案:

答案 0 :(得分:2)

QObject亲子关系和存储持续时间是正交问题,应单独解决。

除非所有拥有的对象都将所有者设置为父级,否则您无法将其他QObject的{​​{1}}移动到另一个线程。因此,通过不设置父级,您过早地限制了父类的功能。

在现代C ++中,具有动态存储持续时间的子QObject应该通过资源管理器保存。这样的管理器可以是智能指针,也可以是拥有对象。回想一下,QObject也是一个QObject容器。因此,甚至没有必要有一个指向子对象的显式成员指针 - 比如你是否只需要在构造所有者期间直接引用该对象。

一般来说,通过让任何成员具有动态存储持续时间,你会过早地处于悲观状态,除非他们的构造函数非常昂贵并且你想要将构造延迟到稍后的时间。

所以,如果你没有使用PIMPL idiom,那么所有成员都应该在对象本身中拥有自动存储持续时间:

QObject

否则,它们属于PIMPL:

// A.h
class A : public QObject {
  Q_OBJECT
  QSerialPort m_port { this };
  QThread m_thread { this };
  ....
};

还应该指出,使用指向前向声明的不完整类型的指针以“加速”编译或“减少依赖性”是一种反模式。如果您愿意在头文件中公开实现细节,只需按值保存所有成员 - 如上面的第一个示例所示。如果您担心过多的依赖关系并希望隐藏您的实现,请使用PIMPL。指向前向声明类的指针的“中间道路”会强加额外的动态存储分配,因此是一种不灵活的怪物,无助于任何人,也没有任何人。

// A.h
class APrivate;
class A : public QObject { ... };

// A.cpp
#include "A.h"
class APrivate {
public:
  A * const q_ptr;
  QSerialPort m_port { q_ptr };
  QThread m_thread { q_ptr };  
  APrivate(A * q) : q_ptr(q) {}
};

答案 1 :(得分:1)

父/子机制不仅仅是在父对象被销毁时删除对象。例如,子对象将始终在与其父对象相同的线程上运行,如果父对象线程发生更改,则子对象也将移动。但只是众多例子中的一个。如果您使用smart_ptr<B> b,则不会拥有这些功能。 Qt中的等价物为QScopedPointer。因此,如果可能的话,最好使用QObject父/子机制。有关整个QObject-parent-child-mechanism的更多信息,请参阅Object Trees & Ownership

关于指针或堆栈之间的区别:大多数QObject都不可复制,不能“移动分配”。在这种情况下,您将需要指针“交换”子对象。但除此之外,它更像是一种风格问题。我个人更喜欢指针式方法。即使您使用的是“堆栈版”,您仍然可以传递父级,以利用所有其他功能。

但最重要的是:似乎你忘了将父传递给QObject构造函数了! (如果你把它留下来简化代码块,请纠正我)。如果你不这样做,你的对象将不会成为它的父母的孩子:

class A : public QObject {
  A(QObject *parent = NULL) : 
    QObject(parent),//Here, because A may become a child of another object some time
    b(new B(this))
  {}


  class B : public QObject {
    B(QObject *parent = NULL) : 
      QObject(parent)//And here it's neccessary
    {}
  };
  B* b;
}