Russian Qt Forum

Qt => Вопросы новичков => Тема начата: lighting от Август 20, 2012, 09:28



Название: Сигналы и слоты в плагинах
Отправлено: lighting от Август 20, 2012, 09:28
Есть задача, программа должна управлять различными железками. Для унификации протокол общения с каждой конкретной железкой выносится в отдельный плагин и подгружается по мере надобности. Насколько я понял интерфейс не может наследоваться от QObject следовательно сигналы и слоты ему недоступны. Со слотами проблема решаемая - их можно вызывать как методы, а вот как быть с сигналами, как получать инфу от плагина?


Название: Re: Сигналы и слоты в плагинах
Отправлено: Странник от Август 20, 2012, 09:46
Есть задача, программа должна управлять различными железками. Для унификации протокол общения с каждой конкретной железкой выносится в отдельный плагин и подгружается по мере надобности. Насколько я понял интерфейс не может наследоваться от QObject следовательно сигналы и слоты ему недоступны. Со слотами проблема решаемая - их можно вызывать как методы, а вот как быть с сигналами, как получать инфу от плагина?
может, доступны - хотя де юре интерфейс должен быть чисто абстрактным (если это требование не отменили в последних версиях, конечно), де факто вы можете без проблем наследоваться от QObject. но если вы борец за расовую чистоту, ваш интерфейс может возвращать указатель на наследника QObject.


Название: Re: Сигналы и слоты в плагинах
Отправлено: Sancho_s_rancho от Август 20, 2012, 11:36
Интерфейс без наследования от QObject, но с
Код:
virtual QObject* pluginObject() = 0;
А в плагине
Код:
class MyClass : public QObject, public ModuleInterface
{
    Q_OBJECT
    Q_INTERFACES(ModuleInterface)
public:
virtual QObject* pluginObject() { return this; }


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 15:42
Если не нравится использование этого метода (мне не нравится):
Код
C++ (Qt)
virtual QObject* pluginObject() { return this; }
 
можно в основной программе делать примерно так:
Код
C++ (Qt)
QPluginLoader loader("plugin");
connect(loader.instance(), SIGNAL(pluginSignal()), SLOT(appSlot()));
 


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 16:00
можно в основной программе делать примерно так:
Код
C++ (Qt)
QPluginLoader loader("plugin");
connect(loader.instance(), SIGNAL(pluginSignal()), SLOT(appSlot()));
 
Чтобы экземпляр плагина мог испускать сигналы (по условию задачи), он все-таки должен быть наследован от QObject.
А т.к. сигналы как и все прочее скорее всего будут унифицированы, наследование должно присутствовать на уровне интерфейса.
Можно конечно перенести объявление сигналов в реализацию интерфейса, но не думаю, что это будет красиво, скорее наоборот.

Поэтому не вижу ничего страшного или некрасивого в том, чтобы интерфейс наследовался от QObject. Технология такая, что естественно, то не безобразно.
Нужно просто в этом интерфейсе делать защищенный конструктор (при необходимости).


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 20, 2012, 16:27
Пробую объявить интерфейс так:

Код
C++ (Qt)
#ifndef INTERFACES_H
#define INTERFACES_H
#include <QObject>
 
class QString;
class CameraInterface : public QObject
{
   Q_OBJECT
public:
   virtual ~CameraInterface() {}
   virtual void powerOn();
   ...
   virtual void extendedCommand(QString command);
 
signals:
   void powerStateCahnged(bool state);
   void backlightStateChanged(bool state);
};
 
Q_DECLARE_INTERFACE(CameraInterface, "ru.myCompany.myApp.cameraInterface/1.0")
 
#endif // INTERFACES_H
 

При попытке сборки валятся ошибки вида:
debug/moc_interfaces.o:moc_interfaces.cpp:(.rdata$_ZTV15CameraInterface[vtable for CameraInterface]+0x38): undefined reference to `CameraInterface::powerOn()'
количеством равным кол-ву виртуальных методов. Насколько я понимаю компилятор пытается найти реализацию вирутальных функций, но зачем он это делает мне не понятно.

Читал вот эту тему http://www.prog.org.ru/topic_8357_0.html никак не могу взять в толк для чего Dendy и Константин советуют в интерфейсе только передавать указатель на создаваемый класс, а не указывать список доступных методов. Я себе представлял что в интерфейсе надо собирать общие для поддерживающих протокол железок методы, чтобы вызывающему плагин приложению было наплевать на реализацию класса для конкретной железки, а советуют делать наоборот  :-\


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 16:36
Насколько я понимаю компилятор пытается найти реализацию вирутальных функций, но зачем он это делает мне не понятно.
Он же не знает, что ты недоучил с++

методы должны быть абстрактными, не?


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 20, 2012, 16:41
да, не все то абстрактно, что виртуально :)


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 16:43
да, не все то абстрактно, что виртуально :)
Заодно QString передавай по константной ссылке.


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 16:46
Чтобы экземпляр плагина мог испускать сигналы (по условию задачи), он все-таки должен быть наследован от QObject.
А я нигде и не утверждал, что MyClass не не должен наследоваться от QObject, как раз наоборот. Я имел ввиду, что метод pluginObject() - лишний, потому, что loader.instance() возвращает ровно то же, что pluginObject().

Пробую объявить интерфейс так:
class CameraInterface : public QObject
CameraInterface НЕ ДОЛЖЕН наследоваться от QObject! От QObject надо наследоваться классом, который реализует абстрактные методы из CameraInterface (см. пример от Sancho_s_rancho с классом MyClass).


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 16:48
CameraInterface НЕ ДОЛЖЕН наследоваться от QObject! От QObject надо наследоваться классом, который реализует абстрактные методы из CameraInterface (см. пример от Sancho_s_rancho с классом MyClass).
Если ты так решил, это не значит, что все должны так делать.
Каким раком тогда moc сгенерит код для сигналов и слотов интерфейса?
Еще как ДОЛЖЕН.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 20, 2012, 16:55
CameraInterface НЕ ДОЛЖЕН наследоваться от QObject! От QObject надо наследоваться классом, который реализует абстрактные методы из CameraInterface (см. пример от Sancho_s_rancho с классом MyClass).
andrew.k меня опередил, но я добавлю - если CameraInterface не будет наследоваться от QObject то как тогда мое приложение использующее плагины узнает о том какие что плагин будет посылать сигналы. Собственно заморочку с плагинами я затеял именно для того чтобы написать нужное кол-во плагинов реализующих конкретный функционал (SonyCamera, AxisCamera, TandbergCamera и т.п.) без необходимости правок в основной программе. Она не должна знать о том что есть все это многообразие, а работать должна со всеми ими через CameraInterface.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 17:23
Можно конечно не наследовать от QObject, а добавить метод возвращающий экземпляр абстрактного рабочего класса (а реализация будет его в наследниках).
Что-нибудь типа
Код
C++ (Qt)
virtual BaseCameraWorker * createWorkerObject() = 0;
Если это действительно необходимо, по соображениям гибкости, то почему нет. Это уже должен автор решать, надо оно ему или нет.
Но не вижу в этом подходе преимуществ (для рассматриваемого примера), ровно как и недостатков в рассматриваемом выше подходе. Меня не пугает интерфейс наследованный от QObject.

Можно абстрагироваться сколько угодно в глубь и в ширь, но как говорится чем круче джип, тем дальше ехать трактору)


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 17:57
Каким раком тогда moc сгенерит код для сигналов и слотов интерфейса?
Еще как ДОЛЖЕН.
Давайте-ка ещё раз и по-спокойнее. Наследоваться от QObject (а так же от CameraInterface) будут классы SonyCamera, AxisCamera, TandbergCamera и т.д. Для них же, а не для CameraInterface, moc сгенерит код для всех их сигналов и слотов. Основному приложению достаточно знать только методы, имеющиеся в CameraInterface и общие для ВСЕХ его наследников сигналы/слоты. В основном приложении на этапе компиляции совсем не нужны moc реализации всего того, что он нагенерит для плагинов.

Вот даже пример набросал.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 18:06
Каким раком тогда moc сгенерит код для сигналов и слотов интерфейса?
Еще как ДОЛЖЕН.
Давайте-ка ещё раз и по-спокойнее. Наследоваться от QObject (а так же от CameraInterface) будут классы SonyCamera, AxisCamera, TandbergCamera и т.д. Для них же, а не для CameraInterface, moc сгенерит код для всех их сигналов и слотов. Основному приложению достаточно знать только методы, имеющиеся в CameraInterface и общие для ВСЕХ его наследников сигналы/слоты. В основном приложении на этапе компиляции совсем не нужны moc реализации всего того, что он нагенерит для плагинов.

Код
C++ (Qt)
class CameraInterface
{
//Q_SIGNALS:
//   void initDone();
// Если тут не будут описаны сигналы
};
 
class SonyCamera : public QObject, public CameraInterface
{
 void doInit()
 {
   ...
  emit initDone();
   // то тут ты не сможешь испускать этот сигнал.
 }
 
// и тогда тебе надо будет описывать его тут:
Q_SIGNALS:
  void initDone();
};
 
class AxisCamera : public QObject, public CameraInterface
{
...
// и еще тут:
Q_SIGNALS:
  void initDone();
};
 
class TandbergCamera : public QObject, public CameraInterface
{
...
// и еще тут:
Q_SIGNALS:
  void initDone();
};
 
//И во всех остальных классах придется делать копипасту.
 
 


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 18:16
Пока писал, увидел, что andrew.k свой пост отредактировал :).
Если нужно получить общий QObject предок для всех SonyCamera и т.п., то можно (и нужно) добавить еще одну прослойку типа CommonCameraInterface в которой описать все нужные сигналы/слоты и прочий общий функционал. А наружу из плагина пусть торчит голый интерфейс.

Код
C++ (Qt)
class CameraInterface
{
};
 
class CommonCamera : public QObject, public CameraInterface
{
signals:
 initDone();
};
 
class SonyCamera : public CommonCamera
{
 void doInit()
 {
   ...
  emit initDone();
 }
};
 


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 18:16
Вот тебе пример как раз.
Я даю тебе интерфейс для плагина и говорю, напиши-ка мне плагин SuperDuperCamera.

Код
C++ (Qt)
#ifndef IPLUGIN_H
#define IPLUGIN_H
 
#include <QtCore>
 
class CameraInterface
{
public:
   virtual ~CameraInterface() {}
 
   virtual void powerOn() = 0;
   virtual void powerOff() = 0;
};
 
Q_DECLARE_INTERFACE(CameraInterface, "ru.prog.test.CameraInterface/1.0")
 
#endif // IPLUGIN_H
 
Ты пишешь, но ничего не работает, а оказывается в реализации нужно было еще сигналы испускать.
А какие нужны сигналы скрыто в реализации, к которой доступ по идее не нужен.
Таким образом ты предлагаешь подглядывая в имеющуюся реализацию делать копипастой.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 18:17
Пока писал, увидел, что andrew.k свой пост отредактировал :).
Если нужно получить общий QObject предок для всех SonyCamera и т.п., то можно (и нужно) добавить еще одну прослойку типа CommonCameraInterface в которой описать все нужные сигналы/слоты и прочий общий функционал. А наружу из плагина пусть торчит голый интерфейс.
Так удали лишнее сообщение, чтобы не смущать никого)


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 18:17
Пока писал, увидел, что andrew.k свой пост отредактировал :).
Если нужно получить общий QObject предок для всех SonyCamera и т.п., то можно (и нужно) добавить еще одну прослойку типа CommonCameraInterface в которой описать все нужные сигналы/слоты и прочий общий функционал. А наружу из плагина пусть торчит голый интерфейс.
Давай пример, как ты это видишь.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 18:24
Мы рассинхронизировались :). Мой пример в моем предыдущем посту.
Ну так я ж из твоего примера взял интерфейс.
Как написать реализацию, имея интерфейс, который я тебе предоставил? Не подсматривая в имеющуюся реализацию никак.

Да какой смысл в описании сигналов в интерфейсе-то?
Если отвечать на этот вопрос, то это будет в четвертый раз в этом топике, наверное.

Я уже другой пример прошу, не рабочий, просто в псевдокоде.
Вот для этой мысли пример:
Если нужно получить общий QObject предок для всех SonyCamera и т.п., то можно (и нужно) добавить еще одну прослойку типа CommonCameraInterface в которой описать все нужные сигналы/слоты и прочий общий функционал. А наружу из плагина пусть торчит голый интерфейс.
Как я понимаю, мы опять получим CommonCameraInterface испускающий сигналы. И в чем разница?


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 18:41
Попытаюсь всё же засинхронизироваться. Удалил один пост, а то нить беседы теряется.
Вот тебе пример как раз.
Я даю тебе интерфейс для плагина и говорю, напиши-ка мне плагин SuperDuperCamera.
Ты пишешь, но ничего не работает, а оказывается в реализации нужно было еще сигналы испускать.
А какие нужны сигналы скрыто в реализации, к которой доступ по идее не нужен.
Таким образом ты предлагаешь подглядывая в имеющуюся реализацию делать копипастой.
Из того, что в CameraInterface будут присутствовать сигналы, никак не вытекает порядок их испускания, так что всё равно нужно будет иметь либо документацию, либо пример.
В моём варианте имея CommonCamera ты получишь то, чего тебе не хватало в CameraInterface, а кроме того можешь еще часть общей для всех камер логики в нем реализовать. Например, флаг m_power.

Как я понимаю, мы опять получим CommonCameraInterface испускающий сигналы. И в чем разница?
Разница в том, что из plugin dll в этом случае будет торчать наружу только голый интерфейс. Этот плагин (теоретически) можно даже будет использовать и в приложении без Qt, и даже без С++.
Кроме того, честно говоря я не уверен, что конструкция вида
Код
C++ (Qt)
class CameraInterface : public QObject
{
   Q_OBJECT
public:
   virtual ~CameraInterface() {}
   virtual void powerOn();
};
 
Q_DECLARE_INTERFACE(CameraInterface, "ru.myCompany.myApp.cameraInterface/1.0")
 
легитимна, поскольку:
1. Making an application extensible through plugins involves the following steps:
Define a set of interfaces (classes with only pure virtual functions) used to talk to the plugins.

Здесь мы делаем CameraInterface, который и экспортируется из плагина.
2. Writing a plugin involves these steps:
Declare a plugin class that inherits from QObject and from the interfaces that the plugin wants to provide.

Здесь мы имеем CommonCamera или SonyCamera, порождённую как от CameraInterface, так и от QObject.
То есть если вариант с class CameraInterface : public QObject сейчас и работает, то это происходит вопреки требованиям Qt developer и совсем не факт, что будет работать и далее.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 19:00
В с++ интерфейс уже сам по себе довольно абстрактное понятие (это просто особого вида класс), для него нет специальной языковой конструкции.
Поэтому это работает и будет работать.
Поэтому я не вижу никакого смысла, разделять общий класс на два уровня.

Поэтому это:
Код
C++ (Qt)
class CameraInterface
{
};
 
class CommonCamera : public QObject, public CameraInterface
{
signals:
 initDone();
};
ничем не отличается от этого:
Код
C++ (Qt)
class CameraInterface : public QObject
{
signals:
 initDone();
};
Кроме дополнительного уровня иерархии, призванного избавить класс нареченный "интерфейсом" не иметь сигналов и не более.

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


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 20, 2012, 20:05
Предлагаю на этом и остановиться, дабы не уподобляться "тому, чье имя нельзя называть вслух" и чья цитата у тебя в подписи. Кстати, странно, что он тут ещё не отписался. Если у топикстартера ко мне вопросы есть - отвечу, если нет - откланиваюсь.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 20, 2012, 20:15
Предлагаю на этом и остановиться, дабы не уподобляться "тому, чье имя нельзя называть вслух" и чья цитата у тебя в подписи. Кстати, странно, что он тут ещё не отписался. Если у топикстартера ко мне вопросы есть - отвечу, если нет - откланиваюсь.
Согласен. В общем-то все понятно.
Спасибо за дискуссию.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 20, 2012, 23:34
Если у топикстартера ко мне вопросы есть - отвечу, если нет - откланиваюсь.
Да вопрос есть - мне непонятен сам принцип используемого вами подхода. Попробую изложить на мой взгяд должно выглядеть решение, а вы ответте где я ошибаюсь. Имеется основная программа, в которой описаны все интерфейсы и которая будет использовать плагины. Все методы, сигналы и слоты общие для какой-то группы железом (напр. Камеры) описаны в интерфейсе и таким образом доступны из основной программы. Может быть масса различных плагинов (sonycam.dll, axiscam.dll) о которых основная программа на этапе компиляции ничего не знает, но которые может использовать благодаря тому что сигналы и слоты их описаны в интерфейсе. Можно конечно создать доп. класс который будет содержать все эти общие сигналы и слоты и отнаследрваться от него но чем этот подход лучше и в чем тогда предназначение интерфейса?


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 21, 2012, 01:02
Можно конечно создать доп. класс который будет содержать все эти общие сигналы и слоты и отнаследрваться от него но чем этот подход лучше и в чем тогда предназначение интерфейса?
Об этом и речь. Этот доп класс и есть CommonCamera в примерах.
Уже ведь обсудили этот вопрос.

Думаю подход с "чистым" интерфейсом более ортодоксальный, хотя при этом сама сущность представляющая "чистый интерфейс" практически мало полезна, т.к. без сигналов скорее всего не будет полностью функциональна, и практическую ценность в этой тройке будет представлять уже CommonCamera.
В общем я это уже писал выше.

Может спецы 80 уровня выскажут свое мнение? Без иронии, Пантер, Igors и другие? Константина не упоминаю, т.к. еще не прочитал внимательно тред на 4 страницах по этому поводу. Не успел. У него вообще другой подход.
По-моему разницы вообще 0, а три класса это на 50% больше чем два)


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 21, 2012, 08:04
Все методы, сигналы и слоты общие для какой-то группы железом (напр. Камеры) описаны в интерфейсе и таким образом доступны из основной программы.
Мы путаемся в терминологии. Интерфейс с точки зрения С++ - класс, состоящий исключительно из абстрактных методов. У него не может быть сигналов и слотов, поскольку они - принадлежность QObject.

Я уже цитировал документацию Qt про плагины и роль интерфейсов в них.
В исходниках Qt из 155 *.h файлов со словом Q_INTERFACE в качестве интерфейса в 154 случаях выступает "голый" класс из набора абстрактных виртуальных методов.
Правда есть один - demos\mobile\quickhit\plugins\levelplugininterface.h в котором интерфейсный класс является потомком QObject, но никаких сигналов/слотов в нём нет, так что зачем это сделано - мне не ведомо.

Если у тебя всё работает и без них (т.е. интерфейс в твоём понимании - это объект, порождённый от QObject и содержащий некий набор абстрактных методов) и тебя это устраивает - можешь не заморачиваться "кошерными" подходами.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 21, 2012, 11:19
Все методы, сигналы и слоты общие для какой-то группы железом (напр. Камеры) описаны в интерфейсе и таким образом доступны из основной программы.
Мы путаемся в терминологии. Интерфейс с точки зрения С++ - класс, состоящий исключительно из абстрактных методов. У него не может быть сигналов и слотов, поскольку они - принадлежность QObject.
Хорошо, а если не использовать терминологию с++. Ну назовем этот класс не CameraInterface, а, например, BaseCamera и не будем говорить, что это не с++ интерфейс, а скажем, что это просто абстрактный класс. Что-то изменится? Кошерности прибавится?

UPD. Черт. Получится формально мы не сможем использовать Q_DECLARE_INTERFACE :)

Если у тебя всё работает и без них (т.е. интерфейс в твоём понимании - это объект, порождённый от QObject и содержащий некий набор абстрактных методов) и тебя это устраивает - можешь не заморачиваться "кошерными" подходами.
UPD. Посмотрел. У нас в проекте используются оба подхода :) Все работает.

В общем ОК.


Название: Re: Сигналы и слоты в плагинах
Отправлено: Igors от Август 21, 2012, 11:35
Пантер, Igors и другие?
Если сам с этим не работал, то лучше помолчать и послушать :)

Прочитав тему непонятно в чем проблема. Ну напр класс QAbstractButton сидит в dll и никаких moc в проекте не создает, но сигналы и слоты имеет. Про BasicInterface ничего не знаю, но интерфейсный метод может вернуть указатель на такой объект - ну и крутить с ним слоты/сигналы. Не вижу здесь никаких неудобств, а может так и повыгоднее - разные плагины, разные сигналы


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 21, 2012, 11:45
Пантер, Igors и другие?
Если сам с этим не работал, то лучше помолчать и послушать :)

Прочитав тему непонятно в чем проблема. Ну напр класс QAbstractButton сидит в dll и никаких moc в проекте не создает, но сигналы и слоты имеет.
Потому что все это уже "сидит" в самой dll.

Про BasicInterface ничего не знаю, но интерфейсный метод может вернуть указатель на такой объект - ну и крутить с ним слоты/сигналы. Не вижу здесь никаких неудобств, а может так и повыгоднее - разные плагины, разные сигналы
Что ж хорошего будет в том, что если все плагины будут по-разному себя вести?
Они на то и плагины, чтобы интерфейсно выглядеть одинаково для ПО.


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 21, 2012, 12:38
Что-то изменится? Кошерности прибавится?
Под "кошерностью" в данном случае понимаю строгое следование документации Qt.
Но раз они сами себе позволяют ей не следовать и у вас
Все работает. В общем ОК.
то и спорить в общем-то не о чем.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 21, 2012, 21:23
Мы путаемся в терминологии. Интерфейс с точки зрения С++ - класс, состоящий исключительно из абстрактных методов. У него не может быть сигналов и слотов, поскольку они - принадлежность QObject.
Это понятно, в данном случае вопрос сугубо практический. Я уже сейчас накидал порядка 15 интерфейсов для своих нужд, и думаю их число будет расти. Если делать все "кошерно" то это будет уже 30 классов, и у меня возникли сомнения - надо-ли плодить столько сущностей. Собственно вопрос в том какие плюсы и минусы у обоих подходов, чего я лишусь если не буду выделять отдельные абстрактные интерфейсы и отдельные base классы?[/quote]
Если у тебя всё работает и без них (т.е. интерфейс в твоём понимании - это объект, порождённый от QObject и содержащий некий набор абстрактных методов) и тебя это устраивает - можешь не заморачиваться "кошерными" подходами.
Ну меня-то все устраивает, но вот будет ли все работать это как раз и вопрос. Не хочется наступать на грабли в середине пути, поэтому и спросил у людей которые уже возможно прошли по нему раньше меня - есть-ли в таком подходе скрытые грабли? :)


Название: Re: Сигналы и слоты в плагинах
Отправлено: Igors от Август 21, 2012, 22:08
Это понятно, в данном случае вопрос сугубо практический. Я уже сейчас накидал порядка 15 интерфейсов для своих нужд, и думаю их число будет расти.
А откуда такое обилие? Они что, не укладываются в единый интерфейс/класс плагина или как?


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 21, 2012, 22:47
А откуда такое обилие? Они что, не укладываются в единый интерфейс/класс плагина или как?
Ну так железки разные, функционал и возможности у них тоже разные. Напр. камеры могут Pan/Tilt  Zoom и т.п. видеокоммутатор может переключать входы на выходы и т.д.
Если конечно рассматривать "кошерный" вариант то можно обойтись одним интерфейсом для всего, но кроме ссылки на конкретный базовый класс тогда в этот интерфейс ничего не засунешь.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 21, 2012, 23:12
Провел эксперимент.
Если убрать макрос Q_DECLARE_INTERFACE, то проект плагина (я взял проект хокса для тестов) не компилится.
Ругается, что у интерфейса нет макроса Q_OBJECT. Если его добавить, то ругается, что не может преобразовать интерфейс к QObject *
Дальше добавляю наследование от QObject. И больше не ругается. И плагин компилится.
Хоть использовать его и нельзя, т.к. макрос Q_DECLARE_INTERFACE определяет какие-то функции, которые видимо необходимы метаобъектной системе, и без него система работать не будет.
Отсюда я делаю вывод, что интерфейс в Qt имеет все-таки метаобъектную природу и рассматривается метаобъектной системой как QObject.
Таким образом интерфейс в Qt не равен чистому интерфейсу c++. Moc используя макросы его "тюнингует".
И отсюда главный вывод, что использование сигналов в интерфейсах Qt допустимо.

PS. что делает сам макрос мне не очень понятно. Определяет какие-то функции. Мне не понятен синтаксис препроцессора.
Код
C++ (Qt)
#  define Q_DECLARE_INTERFACE(IFace, IId) \
   template <> inline const char *qobject_interface_iid<IFace *>() \
   { return IId; } \
   template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
   { return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \
   template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
   { return reinterpret_cast<IFace *>((object ? const_cast<QObject *>(object)->qt_metacast(IId) : 0)); }


Название: Re: Сигналы и слоты в плагинах
Отправлено: xokc от Август 22, 2012, 08:15
Я уже сейчас накидал порядка 15 интерфейсов для своих нужд, и думаю их число будет расти. Если делать все "кошерно" то это будет уже 30 классов
То есть 15 различных ТИПОВ устройств? Или всё таки 15 вариантов одного и того же типа (камер, насколько я понимаю)?

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

В моих проектах, и это понятно, я использую промежуточный класс. Причём он покрывает общий функционал наследников (в моём случае - это около 50 различных вариантов радиоприёмных устройств, подключаемых к COM порту) и лежит в отдельной DLL. Кстати, в этой же DLL скрыт и собственно код для работы с COM-портом.
Поскольку в этом случае в плагинах остаётся только тот функционал, который и отличает одно устройство от другого, то они получаются очень компактными, а их общую логику я могу изменять заменой той самой DLL без перекомпиляции плагинов.
Схема работает в реальных проектах года примерно три, пережила смену нескольких версий Qt и перспектив её пересматривать у меня оснований нет.

PS. что делает сам макрос мне не очень понятно. Определяет какие-то функции. Мне не понятен синтаксис препроцессора.
Ну так судя по всему он и добавляет самое главное - преобразование интерфейсного наследника к классу QObject.


Название: Re: Сигналы и слоты в плагинах
Отправлено: Igors от Август 22, 2012, 10:15
Ну так судя по всему он и добавляет самое главное - преобразование интерфейсного наследника к классу QObject.
Ну "в общих чертах" да, но сам бы такое я написать не смог. Что такое template <>  ???

Ну так железки разные, функционал и возможности у них тоже разные. Напр. камеры могут Pan/Tilt  Zoom и т.п. видеокоммутатор может переключать входы на выходы и т.д.
Хмм.. ну а тогда в чем смысл плагинов что обычно подразумевает расширение возможностей без изменений хоста? Не лучше ли делать это статик либой, возможно вынося в плагины только независимую часть (как советует  xokc) пусть и недостаточную для поддержки "всего".


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 22, 2012, 10:32
В моих проектах, и это понятно, я использую промежуточный класс. Причём он покрывает общий функционал наследников (в моём случае - это около 50 различных вариантов радиоприёмных устройств, подключаемых к COM порту) и лежит в отдельной DLL. Кстати, в этой же DLL скрыт и собственно код для работы с COM-портом.
Поскольку в этом случае в плагинах остаётся только тот функционал, который и отличает одно устройство от другого, то они получаются очень компактными, а их общую логику я могу изменять заменой той самой DLL без перекомпиляции плагинов.
Схема работает в реальных проектах года примерно три, пережила смену нескольких версий Qt и перспектив её пересматривать у меня оснований нет.
Никто ж не говорил, что она плохая. Не плохая, ни хорошая, имхо подходы по сути одинаковы. Только в одном случае, вид с боку.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Август 23, 2012, 11:36
То есть 15 различных ТИПОВ устройств? Или всё таки 15 вариантов одного и того же типа (камер, насколько я понимаю)?
15 различных типов - камеры, видеокоммутаторы, устройства отображения и т.д. И в каждом типе может быть 1-10 различных конкретных железок, напр. камеры от sony, axis, polycom и т.д.
Хмм.. ну а тогда в чем смысл плагинов что обычно подразумевает расширение возможностей без изменений хоста? Не лучше ли делать это статик либой, возможно вынося в плагины только независимую часть (как советует  xokc) пусть и недостаточную для поддержки "всего".
Чтобы было понятнее опишу суть проблемы детальнее. Есть набор различного оборудования которым надо управлять, оборудование это различных типов, и различных вендоров в пределах одного типа. Все это оборудование образует единое целое - мультимедийная студия, которой необходимо управлять целиком. Таких студий с различным набором железок много, и моя цель - написать программу, которая будет брать из конфига список оборудования, характерного для данной конкретной студии и имея интерфейсы к типам устройств и плагины для каждой конкретной железки управлять ими всеми. Причем этой самой программе не нужно знать что есть конкретные железки, скажем камера Sony EVI HD 7, ей достаточно знать что есть интерфейс CameraInterface и получив из конфига имя плагина для данной железки создать экземпляр класса который будет ею управлять. В таком случае для адаптации к конкретному набору оборудования необходимо будет только создать соответствующий конфиг и дописать необходимые плагины для железок, изменения самой программы не потребуется.


Название: Re: Сигналы и слоты в плагинах
Отправлено: LisandreL от Август 23, 2012, 11:50
Ну "в общих чертах" да, но сам бы такое я написать не смог. Что такое template <>  ???
Специализация шаблона:
http://www.parashift.com/c++-faq/template-specialization.html
http://www.parashift.com/c++-faq/template-specialization-example.html


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 23, 2012, 12:52
Ну "в общих чертах" да, но сам бы такое я написать не смог. Что такое template <>  ???
Специализация шаблона:
http://www.parashift.com/c++-faq/template-specialization.html
http://www.parashift.com/c++-faq/template-specialization-example.html
О спасибо! А то не нашел.


Название: Re: Сигналы и слоты в плагинах
Отправлено: Igors от Август 23, 2012, 14:50
Ну "в общих чертах" да, но сам бы такое я написать не смог. Что такое template <>  ???
Специализация шаблона:
http://www.parashift.com/c++-faq/template-specialization.html
http://www.parashift.com/c++-faq/template-specialization-example.html
С этим я в курсе, даже сам неск раз применял. Но я думал сначала нужна полная спецификация класса (template <class T>) а потом уже специализация (template <>). А где же у них полная? Или можно и без полной? Словом - растерялся солдат  :)

Спасибо


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Август 23, 2012, 15:15
Ну "в общих чертах" да, но сам бы такое я написать не смог. Что такое template <>  ???
Специализация шаблона:
http://www.parashift.com/c++-faq/template-specialization.html
http://www.parashift.com/c++-faq/template-specialization-example.html
С этим я в курсе, даже сам неск раз применял. Но я думал сначала нужна полная спецификация класса (template <class T>) а потом уже специализация (template <>). А где же у них полная? Или можно и без полной? Словом - растерялся солдат  :)
Полная находится в qobject.h
Код
C++ (Qt)
template <class T>
inline T qobject_cast(QObject *object)
{
#if !defined(QT_NO_QOBJECT_CHECK)
   reinterpret_cast<T>(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(object));
#endif
   return static_cast<T>(reinterpret_cast<T>(object)->staticMetaObject.cast(object));
}
 
template <class T>
inline T qobject_cast(const QObject *object)
{
#if !defined(QT_NO_QOBJECT_CHECK)
   reinterpret_cast<T>(object)->qt_check_for_QOBJECT_macro(*reinterpret_cast<T>(const_cast<QObject *>(object)));
#endif
   return static_cast<T>(reinterpret_cast<T>(object)->staticMetaObject.cast(object));
}
 
 
template <class T> inline const char * qobject_interface_iid()
{ return 0; }
 
Если, конечно, я правильно все понял.


Название: Re: Сигналы и слоты в плагинах
Отправлено: LisandreL от Август 23, 2012, 15:23
С этим я в курсе, даже сам неск раз применял. Но я думал сначала нужна полная спецификация класса (template <class T>) а потом уже специализация (template <>). А где же у них полная? Или можно и без полной?
Полная в qobject.h:
Код
C++ (Qt)
template <class T> inline const char * qobject_interface_iid()
{ return 0; }
Ну а вообще объявление, насколько я помню, обязательно, а обобщённая реализация нет, могут быть одни специализации.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Сентябрь 07, 2012, 15:50
Не думал что придется возвращаться к этой теме, но пришлось - при попытке добавить наследование интерфейса от QObject получаю ошибку при сборке плагина QObject is ambiguous base of [имя плагина]. Насколько я понял компилер не знает какой из конструкторов QObject ему использовать. andrew.k подскажи как ты решал эту проблему?
Интерфейс:
Код
C++ (Qt)
#ifndef TESTINTERFACE_H
#define TESTINTERFACE_H
 
#include <QObject>
 
class QString;
class QStringList;
 
class TestInterface : QObject{
   Q_OBJECT
public:
   virtual ~TestInterface() {}
   virtual QStringList operations() const = 0;
   virtual QString operation(const QString& strOperation ) = 0;
signals:
   void operationSelected(QString oper);
};
 
Q_DECLARE_INTERFACE(TestInterface, "ru.prog.PluginTest.TestInterface/1.1")
 
#endif // TESTINTERFACE_H
 

Плагин
Код
C++ (Qt)
#ifndef FRUITS_H
#define FRUITS_H
 
#include <QtCore>
#include "fruits_global.h"
#include "../TestInterface.h"
 
class FRUITSSHARED_EXPORT Fruits : public QObject, public TestInterface {
   Q_OBJECT
   Q_INTERFACES(TestInterface)
 
public:
   explicit Fruits(QObject *parent = 0);
   virtual ~Fruits();
 
   QStringList operations() const;
   QString operation(const QString &strOperation);
 
signals:
   void operationSelected(QString oper);
};
 
#endif // FRUITS_H
 


Код
C++ (Qt)
#include "fruits.h"
#include <QDebug>
 
Fruits::Fruits(QObject *parent) : QObject(parent)
{
}
 
Fruits::~Fruits()
{
 
}
 
QStringList Fruits::operations() const
{
   return QStringList() << "apple" << "grape" << "banana" << "kiwi";
}
 
QString Fruits::operation(const QString &strOperation)
{
   emit operationSelected(strOperation);
   if (strOperation == "apple") {return QString("i'm a Apple");}
   else if (strOperation == "grape") {return QString("i'm a Grape");}
   else if (strOperation == "banana") {return QString("i'm a Banana");}
   else if (strOperation == "kiwi") {return QString("i'm a Kiwi");}
   else {qDebug() << "unsupported operation"; return QString();}
}
 
Q_EXPORT_PLUGIN2(TestInterface, Fruits)
 


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Сентябрь 07, 2012, 16:45
знает какой из конструкторов QObject ему использовать. andrew.k подскажи как ты решал эту проблему?
Зачем ты при наследовании интерфейса добавляешь наследование от QObject. У тебя получается множественное наследование от QObject.

Вот так должно быть.
Код
C++ (Qt)
class FRUITSSHARED_EXPORT Fruits : public TestInterface {
   Q_OBJECT
   Q_INTERFACES(TestInterface)
 

QObject is ambiguous base of [имя плагина]. Насколько я понял компилер не знает какой из конструкторов QObject ему использовать.
Именно!


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Сентябрь 10, 2012, 11:27
Тогда компилятор ругается что класс QObject ему недоступен при экспорте плагина:
Код
C++ (Qt)
class FRUITSSHARED_EXPORT Fruits : public TestInterface {
   Q_OBJECT
   Q_INTERFACES(TestInterface)
Код
C++ (Qt)
#include "fruits.h"
 
Fruits::Fruits()
{
}
 
Fruits::~Fruits()
{
}
 
...
 
Q_EXPORT_PLUGIN2(TestInterface, Fruits)
 
На последнюю строку он ругается
..\fruits\fruits.cpp:28: ошибка: 'QObject' is an inaccessible base of 'Fruits'


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Сентябрь 10, 2012, 12:46
Не знаю, почему не компилится. Возможно ты забыл убрать вызов конструктора QObject?
Вот по-быстрому переделал пример хокса.
Компилится и работает.


Название: Re: Сигналы и слоты в плагинах
Отправлено: lighting от Сентябрь 11, 2012, 13:50
ответ оказался банальным - H-ник интерфейса не был включен в pro-файл плагина, просто включен в h-ник самого плагина. При этом если убрать QObject из интерфейса то все собирается, а если добавить QObject то собирается только после того как интерфейс добавить в plugin.pro.


Название: Re: Сигналы и слоты в плагинах
Отправлено: andrew.k от Сентябрь 11, 2012, 16:23
ответ оказался банальным - H-ник интерфейса не был включен в pro-файл плагина, просто включен в h-ник самого плагина. При этом если убрать QObject из интерфейса то все собирается, а если добавить QObject то собирается только после того как интерфейс добавить в plugin.pro.
Это понятно.
h-ник должен быть в pro-файле обязательно, если в нем есть Q_OBJECT. Иначе как до него доберется moc?
А без moc ничего не выйдет.