Я хочу сделать класс, похожий на QPointer
(или его подкласс), который будет издавать сигнал всякий раз, когда изменяется внутренний указатель.
К сожалению мне нужно наследовать QObject
класс, чтобы иметь возможность излучать сигналы, а также я думаю, что мне нужно использовать шаблоны, чтобы иметь возможность хранить указатель определенного типа. Но согласно этот вопрос нельзя смешивать QObject
с шаблонами.
Любая идея, как сделать мой класс, который отслеживает изменения внутреннего указателя?
Вы должны использовать 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);
//...
}
В зависимости от реализации вашего интеллектуального указателя, вы можете вообще не использовать старый указатель и просто подавать сигнал без аргументов. Возможно, нет никакой причины для дальнейшего доступа к старому объекту, особенно если он собирается быть удаленным.
Других решений пока нет …