Qt:当QPointer更改时发出信号

3
我想创建一个类,类似于 QPointer(或其子类),每当内部指针发生更改时都会发出信号。
不幸的是,我需要继承 QObject 类才能发出信号,并且我认为我需要使用模板来存储特定类型的指针。但是根据这个问题,将 QObject 与模板混合使用是不可能的。
有什么方法可以制作跟踪内部指针更改的类吗?

只是提出一个想法:创建一个继承QObject的类,它只有一个函数emitPointerChange,该函数实际上会发出信号,并在模板类中组合此自定义发射器对象。然后,您需要将插槽连接到MyQPointer::m_emitter指针而不是QPointer本身,这是可能的吗? - ymoreau
1个回答

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子类,则发出销毁信号)。

如果您选择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*)));

传递到槽中的空指针是重置之前持有的T指针。为了简化必要的强制转换,您可以向Pointer类添加一个辅助方法,如下所示:
T * cast(void * p) { return static_cast<T*>(p); }

这样,在一个槽函数中,对于一个Pointer<QLabel> pointer,可以这样使用:
void Form::pointerreset(void * p)
{
    QLabel * label = pointer.cast(p);
    //...
}

根据您的智能指针实现,您可以考虑不再使用旧指针,只需发出没有参数的信号。也许没有理由进一步访问旧对象,特别是如果它即将被删除。


与此同时,我找到了完全相同的解决方案 :) 唯一的痛点是信号reset(void*)没有提供模板指针类型,而只有一个通用的void *指针。在这种情况下,添加一个Pointer类的getter比总是在参数中重新输入指针更加舒适。无论如何,感谢您的解决方案! - Honza Vojtěch
1
当您访问已保留的实例时,在接收到信号后,您是否100%确定它是指旧实例而不是新设置的实例?我会传递void指针并使用我添加到答案中的辅助方法进行转换。 - p-a-o-l-o
非常好的解决方案,+1 - Honza Vojtěch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接