哪个更好?如果子对象是类的成员,则为子对象设置父对象
What is better? Setup QObject parent for child or not if child is member of class?
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;
}
QObject
亲代与保存期是正交关系,应分别处理
你不能将持有其他QObject
的QObject
移动到另一个线程,除非所有拥有的对象都将所有者设置为父对象。因此,如果不设置父类,就过早地限制了父类的功能。
在现代c++中,具有动态存储时间的子QObject
应该通过资源管理器保存。这样的管理器可以是一个智能指针,或者只是拥有对象。回想一下,QObject
也隐式地是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) {}
};
还应该指出,为了"加速"编译或"减少依赖"而使用指向前向声明的不完整类型的指针是一种反模式。如果您愿意在头文件中公开实现细节,只需按值保留所有成员即可——如上面的第一个示例所示。如果您担心过多的依赖关系并希望隐藏您的实现,请使用PIMPL。指针指向前向声明类的"中庸之道"会给您带来额外的动态存储分配,因此是一个不灵活的怪物,对任何事情都没有帮助。
// DO NOT WRITE CODE LIKE THIS!!
class QSerialPort;
class QThread;
class A : public QObject {
Q_OBJECT
QSerialPort * m_port;
QThread * m_thread;
...
};
// DO NOT WRITE CODE LIKE THIS!!
父/子机制不仅仅是在它的父类被销毁时删除对象。例如,子对象将始终在与其父线程相同的线程上运行,如果父线程更改,子对象也将移动。但这只是众多例子中的一个。如果您使用的是smart_ptr<B> b
,则不会具有这些功能。Qt中与此等价的是QScopedPointer
。因此,如果可能的话,最好使用QObject父/子机制。关于整个qobject -parent-child机制的更多信息,请参见对象树。所有权
关于指针和堆栈之间的区别:大多数qobject是不可复制的,不能"移动赋值"。在这种情况下,您将需要指针来"交换"子对象。但除此之外,这更多的是一个风格问题。我个人更喜欢指针方法。即使你使用的是"堆栈版本",你仍然可以传递父版本,以利用所有其他功能。
但最重要的是:您似乎忘记将parent传递给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;
}
- 指向设备对象成员的指针
- 访问由unique_ptr传递的对象成员
- 引用对象成员函数的成员函数
- 将 C# 对象(包含静态对象成员)作为参数传递给 C++/CLI 程序
- Lua C API - 从C++分配和使用类的对象成员
- Rapidjson 遍历并获取复杂 JSON 对象成员的值
- 类对象成员变量在调用函数时不会更改
- 对象成员变量还是继承
- C++多态性:有没有办法找到对象成员函数的地址?
- 重载对象成员的比较运算符
- 获取未初始化对象成员的地址是否定义良好?
- 在优先级队列被推送到队列后,如何编辑对象成员
- 为什么在这里调用析构函数,以及在调用该对象析构函数后如何调用对象成员函数?
- 通过 std::bind 从对象成员检索值
- 保留对象成员变量的本地副本
- 有没有办法为静态对象成员定义一个符合开关标准的常量?
- 没有默认构造函数的对象成员的 wig setter
- 对象成员数组C++默认初始化
- 如何在数组中添加对象成员
- 使用聚合创建和关联两个不同的对象成员