1

I want to pass my objects by reference to their base class:
connect(pCaller, SIGNAL(sig2(const IBase &)), pReceiver, SLOT(slot2(const IBase &)));

But I'm getting run-time error:

QObject::connect: Cannot queue arguments of type 'IBase' (Make sure 'IBase' is registered using qRegisterMetaType().)

Therefore I add:
qRegisterMetaType<IBase>("IBase");

And getting a compile-time error:

error C2259: 'IBase': cannot instantiate abstract class

What's the best way to resolve this issue ?

Alexey Andronov
  • 582
  • 6
  • 28
  • 1
    I think that you are looking for this: http://stackoverflow.com/questions/17943496/declare-abstract-signal-in-interface-class/17943699 – Dmitry Sazonov Feb 25 '16 at 10:22
  • 1
    It seems that it is impossible. From what I understand, Qt requires copy constructor for parameters given by const reference: http://stackoverflow.com/a/8457129/4149835 – Vladimir Bershov Feb 25 '16 at 10:27
  • @VladimirBershov after reading the answer from link you provided I added `Qt::DirectConnection` argument to my `connect` call and it seems to work :) But I'm not sure if it's a "hack" or indeed the right way :) Thanks – Alexey Andronov Feb 25 '16 at 10:51
  • Btw, `Q_DECLARE_METATYPE` + `qRegisterMetaType<>()` – Dmitry Sazonov Feb 25 '16 at 12:50

2 Answers2

3
  1. Your class IBase must be copyable and constructable, if you want to pass it directly (not throught pointer)
  2. You need to register IBase * with Q_DECLARE_METATYPE macro in your header (only in global namespace) - Q_DECLARE_METATYPE( IBase * ). Pointers is a POD type, so they are copyable/constructable.
  3. If you want to pass IBase * between different threads, you need to register class with qRegisterMetaType<IBase *>() call;
  4. It is bad practice to pass pointers throught singals, because it is hard to control lifetime of passed objects.
  5. Good workaround: you may register your type with Q_DECLARE_METATYPE( IBase * ) macro and wrap your variable with QVariant: QVariant wrapper; wrapper.setValue( p ); p = wrapper.value<IBase *>();.
Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
  • 1. I'm going to pass it as a reference (afaik the same as through pointer) 5. Seems fishy as `reinterpret_cast` sledgehammer, thanks tho. I will try to apply your sugesstions a little bit later – Alexey Andronov Feb 25 '16 at 16:36
  • Alexey, you can't decide, how to pass it. It is by Qt design - if you are passing some data type, it must be constructable + copyable. – Dmitry Sazonov Feb 25 '16 at 18:03
  • thanks, that will do. Quick question, why are you using `qRegisterMetaType()` when in qt docs they write `qRegisterMetaType("IBase")`? – Alexey Andronov Feb 26 '16 at 10:39
  • 1
    It is necessary to pass name only for using of Qt reflection. I really don't need it in all my projects :) – Dmitry Sazonov Feb 26 '16 at 10:42
  • @Dimirty Sazonov , would you please give more information of wrap variable with QVariant , I want to pass objects through signal/slot between two threads which those objects are from a child class. – saeed Sep 27 '17 at 09:56
  • @saeed you may ask more exact question and provide an SSCCE. – Dmitry Sazonov Sep 27 '17 at 10:32
  • @Dmirty Sazonov let me work on my problem, If I post a question I will add it's link here. I want to send reference of objects with signal/slot to multiple threads each thread would work on data on it's slot and provide result without changing the source , I am searching for a sample to do it safe and correct – saeed Sep 27 '17 at 11:01
  • @saeed it is not possible to send references between threads or with queued connection. In this case parameters will be copied directly. – Dmitry Sazonov Sep 27 '17 at 11:29
  • @DmitrySazonov could give me a link to read more about using signal/slot in base classes with multiple consumer threads. Maybe I am confused with signal/slot mechanism – saeed Sep 27 '17 at 11:39
  • @saeed 1) http://doc.qt.io/qt-5/signalsandslots.html 2) http://doc.qt.io/qt-5/threads-qobject.html – Dmitry Sazonov Sep 27 '17 at 11:40
0

You're getting this error because the caller and receiver live in different threads. Cross-thread slot invocations need to be able to copy all of the arguments. Since you're passing a base type by reference, there's generally no way to copy it :(

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • I added `Qt::DirectConnection` argument to my `connect` call and now it makes no copies. What do you think about that? – Alexey Andronov Feb 26 '16 at 02:21
  • Actual values are of types derived from `IBase`. Sorry I didn't mention it, thought it was obvious :) – Alexey Andronov Feb 26 '16 at 02:31
  • @AlexeyAndronov "I added Qt::DirectConnection argument to my connect call and now it makes no copies. What do you think about that?" Is the slot thread-safe? If it is, it'll of course work. "Actual values are of types derived from IBase" So? Yes, it is obvious, and my answer takes it into account, of course :) You can make `IBase` copyable using the virtual constructor idiom. – Kuba hasn't forgotten Monica Feb 26 '16 at 14:30