3

我想创建一个类似于QPointer(或子类)的类,只要内部指针发生变化,它就会发出一个信号。

不幸的是,我需要继承QObject类才能发出信号,而且我认为我需要使用模板来存储特定类型的指针。但是根据这个问题,不可能QObject与模板混合。

知道如何让我的类跟踪内部指针的变化吗?

4

1 回答 1

3

当你想保护一个子类实例时,你应该使用QPointer 。如果引用的指针被删除,QPointer 设置为:QObject0

QLabel * label = new QLabel();
QPointer pointer = label;
delete label;
if(pointer) //false
{
//...

由于持有的对象是一个 QObject 子类,您可以将一个槽连接到它的destroyed信号,以跟踪它何时被删除(并且 QPointer 设置为零)。

相反,如果 aQPointer被重新分配,则不会发出被破坏的信号

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*)));

传递给槽的 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);
    //...
}

根据您的智能指针实现,您可以考虑根本不使用旧指针,而只发出一个不带参数的信号。也许没有理由进一步访问旧对象,尤其是在它即将被删除的情况下。

于 2018-02-28T10:07:58.033 回答