25

I have a fairly complex set of C++ classes that are re-written from Java. So each class has a single inherited class, and then it also implements one or more abstract classes (or interfaces).

Is it possible to use qobject_cast() to convert from a class to one of the interfaces? If I derive all interfaces from QObject, I get an error due to ambiguous QObject references. If however, I only have the base class inherited from QObject, I can't use qobject_cast() because that operates with QObjects.

I'd like to be able to throw around classes between plugins and DLLs referred to by their interfaces.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Timothy Baldridge
  • 10,455
  • 1
  • 44
  • 80
  • As I'm reading more into the docs, I'm not sure what I want to do is possible...and that's not good. I could use the RTTI based .dynamicCast() but it doesn't sound like that would always work across DLL boundaries. – Timothy Baldridge Sep 16 '10 at 12:54
  • I found this: http://stackoverflow.com/questions/3201273/qt-moh-multiple-inheritance-problem so I guess it's already been asked. – Timothy Baldridge Sep 16 '10 at 13:10

1 Answers1

31

After some research and reading the qobject_cast documentation, I found this:

qobject_cast() can also be used in conjunction with interfaces; see the Plug & Paint example for details.

Here is the link to the example: Plug & Paint.

After digging up the interfaces header in the example, I found the Q_DECLARE_INTERFACE macro that should let you do what you want.

First, do not inherit QObject from your interfaces. For every interface you have, use the Q_DECLARE_INTERFACE declaration like this:

class YourInterface
{
public:
    virtual void someAbstractMethod() = 0;
};

Q_DECLARE_INTERFACE(YourInterface, "Timothy.YourInterface/1.0")

Then in your class definition, use the Q_INTERFACES macro, like this:

class YourClass: public QObject, public YourInterface, public OtherInterface
{
    Q_OBJECT
    Q_INTERFACES(YourInterface OtherInterface)

public:
    YourClass();

    //...
};

After all this trouble, the following code works:

YourClass *c = new YourClass();
YourInterface *i = qobject_cast<YourInterface*>(c);
if (i != NULL)
{
    // Yes, c inherits YourInterface
}
Venemo
  • 18,515
  • 13
  • 84
  • 125
  • Ahh! Cool. I had tried the Q_DECLARE_INTERFACE, but didn't add the Q_INTERFACES to the derived object. Thanks for the help. – Timothy Baldridge Sep 16 '10 at 13:35
  • @Timothy - I'm happy I could help. I learn something new about Qt every day. :) – Venemo Sep 16 '10 at 13:40
  • 3
    Normally, people use `if (YourInterface *i = qobject_cast(c)) { }`. This ensures that the pointer is never used if it is invalid. – Puppy Sep 16 '10 at 14:54
  • 1
    @DeadMG - Good point, but I don't think putting `=` into an `if` statement is a good practice, because many people confuse it with `==`. – Venemo Sep 16 '10 at 15:10
  • 5
    actually I've seen the pattern above used very commonly. Simply because people don't know the difference between = and == is not a good reason to use or not use it. Just like there's no reason to not use ++i vs i++ simply because they could be confused. – Timothy Baldridge Sep 18 '10 at 03:22
  • @Timothy - If you like it, use it. :) – Venemo Sep 18 '10 at 03:50
  • @Venemo, What about casting upward? YourInterface *i = new YourClass(); YourClass *c = qobject_cast(i); // qobject_cast fails, but with static_cast it works. Should static_cast be used in this case? – krdx May 13 '13 at 11:53
  • @krdx Are you sure that your interface has `Q_DECLARE_INTERFACE` and that your class inherits from `QObject` and lists your interface in `Q_INTERFACES`? – Venemo May 13 '13 at 13:41
  • @Venemo yes. http://pastebin.com/Uwy6AKwB here's my example code. I am porting some C# code to C++(Qt) and I have trouble representing classes that implement (multiple) interfaces. – krdx May 13 '13 at 16:08
  • @Venemo I am trying to model something like this from C#: http://pastebin.com/kF8iPapm (some interface containing methods, and an event, this interface is implemented by an abstract base class, later I have many classes deriving from that abstract base class and finally a factory class.) Of course in this situation, when I have a single interface in C#, on the C++ side I could directly inherit a QObject for the interface and be done with it (IFoo : public QObject), although once I get into implementing many interfaces I will run into trouble. – krdx May 13 '13 at 16:26
  • 1
    @krdx No, your interfaces should definitely not inherit QObject. – Venemo May 13 '13 at 16:38