Russian Qt Forum
Ноябрь 01, 2024, 13:36 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Множественное наследования от QObject или подключения к сигналам не в QObject-а  (Прочитано 3303 раз)
MaxoBik
Гость
« : Июль 23, 2015, 15:13 »

Доброго времени суток.
Есть некий класс(SignalEmiter), унаследованный от QObject, выдающий сигналы. На эти сигналы нужно подписываться в других классах(их много), унаследованных от QObject(на самом деле некоторые из них наследуют от QWidget, но по иерархии классов все равно QObject). Так вот, что бы в каждом из этих классах не печатать что типа такого:
Код:
     void setSignalEmiter(SignalEmiter* semiter){
       if(m_semiter!=NULL){
         /* тут отписываемся от сигналов */
       }
       m_semiter = semiter;
       if(m_semiter!=NULL){
         /* тут подписываемся на сигналы */
       }
    }
protected:
    SignalEmiter* m_semiter;

Я решил использовать базовый класс, от которого должны были наследовать потребители сообщений SignalEmiter:
Код:
class SignalEmiterConsumer : QObject {
    Q_OBJECT
public:
    explicit SignalEmiterConsumer(QObject *parent=0) :
             QObject(parent),
             m_semiter(NULL)
    {
    }
    virtual SignalEmiter* getSignalEmiter(){
        return m_semiter;
    }

    void setSignalEmiter(SignalEmiter* semiter){
       if(m_semiter!=NULL){
         /* тут отписываемся от сигналов */
       }
       m_semiter = semiter;
       if(m_semiter!=NULL){
         /* тут подписываемся на сигналы */
       }
    }
 
protected slots:
    virtual void someSlot1(const QString &location, int exponent)=0;
     ....
    virtual void someSlotN(const QString &location, some_structure* kNumber, int tkNumber)=0;
protected:
     SignalEmiter* m_semiter;
};

Но проблема в том, что как я писал раньше, классы потребители сообщений уже наследуют от QObject, а QObject не позволяет множественное наследования.
Я даже хотел отказаться использовать в базовом классе SignalEmiterConsumer от QObject-а, и подписывания на сигналы с использованием адресов функций вместо слотов(в стиле Qt5), но как оказалось это тоже не возможно - нужно чтобы было наследования от QObject-а, иначе компилятор ругается.
Подскажите - как выполнить поставленную задачу?
« Последнее редактирование: Июль 23, 2015, 15:15 от MaxoBik » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Июль 23, 2015, 15:46 »

Через кросс-приведение, напр
Код
C++ (Qt)
class SignalEmiterConsumer  {
public:
   void setSignalEmiter(SignalEmiter* semiter){
      if(m_semiter!=NULL){
        /* тут отписываемся от сигналов */
      }
      m_semiter = semiter;
      if(m_semiter!=NULL){
        /* тут подписываемся на сигналы */
        QObject * dst = dynamic_cast <QObject *> (this);
        Q_ASSERT(dst);
        QObject::connect(semitter, .., dst, ..);
        ...  
      }
   }
Подразумеваетcя что SignalEmiterConsumer долит множественным наследованием к наследнику QObject. Хотя нужно ли это все? Почему бы не сделать под/от писки просто ф-циями?
Записан
MaxoBik
Гость
« Ответ #2 : Июль 23, 2015, 16:04 »

Да, я так уже пробовал, но начинаются проблемы - говорит не возможности привести к QObject *, пробовал и через  reinterpret_cast с таким же результатом:

Цитировать
'QObject::connect' : none of the 4 overloads could convert all the argument types


т.е.:
Код:
QObject * dst = dynamic_cast <QObject *> (this);
QObject::connect( semitter, &SignalEmiter::someSignal1, dst, &SignalEmiterConsumer::someSlot1 );
ПС сигнатуры слота и сигнала совпадают. Скорей всего проблема в последнем аргументе, но как тут его правильно привести?
Еще пытался и вот так(также SignalEmiterConsumer не наследует от QObject):
Код:

QObject::connect( semitter, &SignalEmiter::someSignal1, &SignalEmiterConsumer::someSlot1 );
Пишут же в Qt5 можно указать просто адрес с функции с совпадающей сигнатурой к сигналу, но у меня такая же ошибка:
Цитировать
'QObject::connect' : none of the 4 overloads could convert all the argument types
« Последнее редактирование: Июль 23, 2015, 16:27 от MaxoBik » Записан
Bepec
Гость
« Ответ #3 : Июль 23, 2015, 16:16 »

Чисто для информации: в Qt 5+ можно привязывать сигналы к обычным функциям. И оно работает спокойно и без затрат.

PS сам размышлял над данной темой, пришёл к выводу, что придётся использовать предсборочный анализ и добавление нужного функционала в классы. (Ну т.е. прога перед началом сборки будет добавлять этот дублирующийся кусок во все классы и/или по условию) Улыбающийся
Записан
MaxoBik
Гость
« Ответ #4 : Июль 23, 2015, 16:31 »

Чисто для информации: в Qt 5+ можно привязывать сигналы к обычным функциям. И оно работает спокойно и без затрат.

Да вот что-то не выходит, может нужно какие заголовки включать или в .pro что-то добавлять?
Ошибка в QtCore\qobject.h у меня:

Код:
    //connect to a function pointer  (not a member)
    template <typename Func1, typename Func2>
    static inline typename QtPrivate::QEnableIf<int(QtPrivate::FunctionPointer<Func2>::ArgumentCount) >= 0, QMetaObject::Connection>::Type
            connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot)
    {
        return connect(sender, signal, sender, slot, Qt::DirectConnection); // <--- вот тут [b]'QObject::connect' : none of the 4 overloads could convert all the argument types[/b]
    }

Судя по всему он ищет ссылку на функцию в sender-е, а она у меня в другом классе.
« Последнее редактирование: Июль 23, 2015, 16:36 от MaxoBik » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #5 : Июль 23, 2015, 16:47 »

Цитировать
'QObject::connect' : none of the 4 overloads could convert all the argument types


т.е.:
Код:
QObject * dst = dynamic_cast <QObject *> (this);
QObject::connect( semitter, &SignalEmiter::someSignal1, dst, &SignalEmiterConsumer::someSlot1 );
При таком раскладе SignalEmiterConsumer не может иметь слотов - он ведь не QObject. Ну это и не нужно (хотя это часто хотят иметь Улыбающийся). Но можно связывать "в старом стиле" через SIGNAL/SLOT макросы.

Вообще этот Consumer выглядит подозрительным/избыточным. Что он должен делать? Связвывать/развязывать? Так это само по себе не основание заводить класс
Записан
MaxoBik
Гость
« Ответ #6 : Июль 23, 2015, 16:59 »

Цитировать
'QObject::connect' : none of the 4 overloads could convert all the argument types


т.е.:
Код:
QObject * dst = dynamic_cast <QObject *> (this);
QObject::connect( semitter, &SignalEmiter::someSignal1, dst, &SignalEmiterConsumer::someSlot1 );
При таком раскладе SignalEmiterConsumer не может иметь слотов - он ведь не QObject. Ну это и не нужно (хотя это часто хотят иметь Улыбающийся). Но можно связывать "в старом стиле" через SIGNAL/SLOT макросы.

Вообще этот Consumer выглядит подозрительным/избыточным. Что он должен делать? Связвывать/развязывать? Так это само по себе не основание заводить класс
Ну как минимум он предоставляет строгую формализацию объекта, показывая ошибки когда мы что-то забыли.
Да подключения-отключения событий кажется тривиальной задачей, но когда у вас скажем 10 разных таких подписчиков, иногда динамически подгружаемых-отгружаемых, каждый раз копипастить один и тот же код - утомляет и вполне может порождать ошибки при копипасте.
Да, "в старом стиле" все подключается, спасибо.
« Последнее редактирование: Июль 23, 2015, 17:11 от MaxoBik » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.125 секунд. Запросов: 22.