我想创建一个类似于QPointer
(或它的子类)的类,它会在内部指针发生变化时发出信号。
不幸的是,我需要继承QObject
类才能发出信号,而且我认为我需要使用模板来存储特定类型的指针。但根据this question,无法将QObject
与模板混合。
知道如何让我的类跟踪内部指针的变化吗?
答案 0 :(得分:3)
如果您希望保护 QObject
子类实例,则应使用QPointer。如果删除了引用的指针,则QPointer将设置为0
:
QLabel * label = new QLabel();
QPointer pointer = label;
delete label;
if(pointer) //false
{
//...
由于被保持对象是QObject子类,因此您可以将一个插槽连接到其destroyed
信号,以跟踪它何时被删除(并且QPointer设置为零)。
如果重新分配QPointer
,则不会发出被破坏的信号
pointer = new QLabel();
以前持有的对象只是没有防范,但没有被删除。
要跟踪指针重置,您最好使用QSharedPointer。
当QSharedPointer
保持对象被清除或重置,并且内部引用计数变为零时,在被保持对象上调用delete
(如果它是QObject子类,则发出被破坏的信号)。 / p>
如果您选择DIY智能指针,我建议使用QObject派生类来发出信号,并在指针类中拥有它的实例:
class Emitter : public QObject
{
Q_OBJECT
public:
Emitter() : QObject(0) {}
void forward(void * p) { emit reset(p); }
signals:
void reset(void *);
};
template <typename T>
class Pointer
{
public:
Pointer() : instance(0){}
void connect(QObject * receiver, const char * slot)
{
QObject::connect(&emitter, SIGNAL(reset(void*)), receiver, slot);
}
void set(T* t)
{
emitter.forward(instance);
instance = t;
}
//...
private:
Emitter emitter;
T * instance;
};
显然,上面的代码不意图作为智能指针实现,只是一个示例,展示如何从类模板中发出信号。
连接一个插槽(比如来自Form类):
Pointer<QLabel> p;
p.connect(this, SLOT(pointerreset(void*)));
传递给插槽的void指针是复位前保持的T指针。为了简化不可避免的强制转换,您可以向Pointer类添加一个这样的辅助方法:
T * cast(void * p) { return static_cast<T*>(p); }
这样,对于Pointer<QLabel> pointer
,在插槽中:
void Form::pointerreset(void * p)
{
QLabel * label = pointer.cast(p);
//...
}
根据您的智能指针实现,您可以考虑根本不使用旧指针,只发出不带参数的信号。也许没有理由进一步访问旧对象,特别是如果它将被删除。