Qt сигнал — предотвращение дублирования кода слота

#c #qt #inheritance #signals-slots #qobject

#c #qt #наследование #сигналы-слоты #qobject

Вопрос:

Я хотел бы поделиться сигналами и, возможно, реализациями слотов между разными классами, но, похоже, Qt этого не допускает.

В принципе, я хотел бы иметь что-то вроде:

 class CommonSignals
  {
  signals:
  void mysignal();
  };

class A : 
    public QObject, 
    public CommonSignals
  {
    Q_OBJECT
  public:
    void doSomething()
      {
      emit mysignal();
      }
  };


class B : 
    public QObject, 
    public CommonSignals
  {
    Q_OBJECT

  public:

    B()
      {
      connect(amp;a, amp;A::mysignal, this, amp;B::mysignal);
      }

    A a;
  };
  

Так что, когда по какой-то причине A испускает сигнал, B тоже испускает тот же сигнал. Это позволяет избежать бесполезной репликации кода и улучшить удобство обслуживания.

Есть идеи?

PS Я пробовал также с виртуальным наследованием, но у меня классические проблемы с qmake

Комментарии:

1. У вас опечатка: connect(amp;a, amp;A::mysignal, this, amp;B::mysignal); исправит вашу ошибку.

2. Я отредактировал вопрос, поверьте мне, проблема была не в этом 🙂

3. CommonSignals не наследует QObject и поэтому не может иметь сигналов, связанных с ним. Вы не видите никаких ошибок или предупреждающих сообщений от moc ?

4. @Jarod42 Вы можете подключить сигнал к другому сигналу, это нормально.

5. @G.M. При множественном наследовании только одному из базовых классов разрешено быть a QObject . Так CommonSignals что не может быть одного. Это означает, что он не может использовать сигналы.

Ответ №1:

Вы не можете этого сделать. QObject не может использоваться с множественным наследованием нескольких QObject баз. Только первый унаследованный класс может быть a QObject . См.:

https://doc.qt.io/qt-5/moc.html#multiple-inheritance-requires-qobject-to-be-first

Поскольку вам нужно, чтобы оба базовых класса были a QObject ( CommonSignals предоставляет сигналы, это должно быть a QObject ), вам не повезло. Ваш единственный вариант здесь — использовать простые старые макросы:

 #define COMMON_SIGNALS 
    void signal1(); 
    void signal2();

class A: public QObject
{
    Q_OBJECT

public:
    // ...

signals:
    COMMON_SIGNALS
};

class B: public QObject
{
    Q_OBJECT

public:
    // ...

signals:
    COMMON_SIGNALS
};
  

Основная проблема со всем этим заключается в том, что Qt использует moc для генерации базового кода для сигналов и слотов. Однако moc — это всего лишь простой препроцессор, который не понимает большую часть C .

Вы могли бы использовать Verdigris, чтобы избавиться от moc:

https://github.com/woboq/verdigris

Это позволяет вам иметь шаблонные QObject классы, например. Я сам не пробовал и, следовательно, не знаю, действительно ли он допускает множественное наследование. Возможно, стоит изучить.

Комментарии:

1. Спасибо за отзыв. Я ищу какое-то обходное решение, потому что я не хотел использовать макросы, кто знает, может быть, есть какой-то трюк, эхе

2. как насчет использования CRTP в некотором роде?

3. @Saturnu Проблема в moc. Он не понимает шаблоны. На самом деле, он не понимает большую часть C . Он просто ищет несколько простых вещей в файлах заголовков. Вы можете попробовать и использовать это, хотя это полностью избавляет от moc: github.com/woboq/verdigris

4. Да, я слышал о Verdigris, спасибо. Возможно, я попробую это в будущем, но я все еще заинтересован в поиске решения этой проблемы. В некоторых случаях мне удалось заставить шаблоны и Qt работать вместе 😉

Ответ №2:

Почему бы просто не перенести наследование из QObject производных классов A и B и в CommonSignals

 class CommonSignals: public QObject {
  Q_OBJECT;
signals:
  void mysignal();
};

class A: public CommonSignals {
  Q_OBJECT;
public:
  void doSomething ()
    {
      emit mysignal();
    }
};

class B: public CommonSignals {
  Q_OBJECT;
public:
  B ()
    {
      connect(amp;a, amp;A::mysignal, this, amp;B::mysignal);
    }
  A a;
};
  

Это не сработает для вас?

Комментарии:

1. Это не позволило бы вам создать, скажем, QLineEdit (или любой другой QObject класс, не производный напрямую QObject ), который предоставляет общие сигналы. Я предполагаю, что это то, что имеет в виду OP.

2. Спасибо за отзыв. Нет, я думаю, это решение не подходит. Цель на самом деле состоит в том, чтобы заставить B расширять другие классы, например, CommonSignals2, CommonSignals3 и т. Д. Как @NikosC. Я не думаю, что это должно работать во всех случаях.

3. ОК. Наверное, я неправильно понял вопрос.