Qt: испускать сигнал при изменении QPointer

Я хочу сделать класс, похожий на QPointer (или его подкласс), который будет издавать сигнал всякий раз, когда изменяется внутренний указатель.

К сожалению мне нужно наследовать QObject класс, чтобы иметь возможность излучать сигналы, а также я думаю, что мне нужно использовать шаблоны, чтобы иметь возможность хранить указатель определенного типа. Но согласно этот вопрос нельзя смешивать QObject с шаблонами.

Любая идея, как сделать мой класс, который отслеживает изменения внутреннего указателя?

3

Решение

Вы должны использовать QPointer когда ты хочешь охрана QObject экземпляр подкласса. Если указанный указатель удален, 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*)));

Указатель 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);
//...
}

В зависимости от реализации вашего интеллектуального указателя, вы можете вообще не использовать старый указатель и просто подавать сигнал без аргументов. Возможно, нет никакой причины для дальнейшего доступа к старому объекту, особенно если он собирается быть удаленным.

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]