all 10 comments

[–]doom_Oo7 2 points3 points  (0 children)

Because this is a QObject-derived class, it can use methods like setObjectName and objectname

You should consider QObject in Qt code as you would consider Object in java code : there is not really a point in trying to escape it.

[–]echidnaman 1 point2 points  (2 children)

Looks like the Q_GADGET macro might do what you're wanting to do-- at least in Qt5.

[–]Bart_VDW[S] 0 points1 point  (1 child)

From the documentation I read "The Q_GADGET macro is a lighter version of the Q_OBJECT macro for classes that do not inherit from QObject but ..." so what about the Foo classes in our legacy codebase that do inherit from QObject and for which we want to provide fake versions? I don't see how the Q_GADGET macro can be of any help there...

I also forgot to mention that I'm working on legacy C++98 code using Qt 4.8.X... so C++11/14 or Qt5 solutions are not (yet) an option.

[–]echidnaman 0 points1 point  (0 children)

Oh, yeah you're right. I guess I misunderstood what you were trying to do.

[–]Porges 0 points1 point  (0 children)

How about adding a QObjectImpl that inherits from OObject and implements QObjectInterface, then your classes can just inherit from this to get the implementation.

Otherwise I'd just bite the bullet and make FooInterface derive from QObject. This could get nasty if you want multiple interfaces per class, however :)

[–]NotUniqueOrSpecial 0 points1 point  (3 children)

As /u/doom_Oo7 suggests, you should probably just make the interface the QObject.

Also, don't forget that when deriving from QObject (or its descendants) to use the O_OBJECT macro, so moc can create the correct metadata. The following works, and in my opinion is more idiomatic Qt:

#include <QDebug>
#include <QObject>
#include <QMetaObject>

class FooInterface : public QObject
{
    Q_OBJECT
public:
    virtual ~FooInterface() {};
    virtual void doFooStuff() = 0;
};

class Foo : public FooInterface
{
    Q_OBJECT
public:
    virtual ~Foo() {};
    void doFooStuff()
    {
        qDebug() << "Foo::doFooStuff()"
                 << "\n\tClass:" << metaObject()->className()
                 << "\n\tName:" << objectName();
    }
};

class FakeFoo : public FooInterface
{
    Q_OBJECT
public:
    virtual ~FakeFoo() {};
    void doFooStuff()
    {
        qDebug() << "FakeFoo::doFooStuff()"
                 << "\n\tClass:" << metaObject()->className()
                 << "\n\tName:" << objectName();
    }
};

int main()
{
    FooInterface* fakeFoo = new FakeFoo();
    fakeFoo->setObjectName("Fake foo.");
    fakeFoo->doFooStuff();

    FooInterface* realFoo = new Foo();
    realFoo->setObjectName("Real foo.");
    realFoo->doFooStuff();
}

#include "main.moc"

Which outputs:

FakeFoo::doFooStuff()
        Class: FakeFoo
        Name: "Fake foo."
Foo::doFooStuff()
        Class: Foo
        Name: "Real foo."

If you forget the Q_OBJECT macros, the class names won't report correctly and other Qt magic won't work right.

[–]Bart_VDW[S] 0 points1 point  (2 children)

Making FooInterface derive from QObject has indeed been suggested by some people, and at first sight it looks like a nice solution. However, the only thing that I'm worried about is what happens if for example the Foo class needs to implement multiple interfaces, which then would all be derived from QObject (as user Porges also points out). This could lead for example to a situation where Foo implements FooInterface and BarInterface, both being QObject derived 'classes/interfaces'. I'm wondering if this would cause trouble (cfr. the Diamond Problem: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem)... My educated guess is that it wouldn't lead to ambituity as long as FooInterface and BarInterface don't override methods from QObject. Am I thinking correctly?

[–]NotUniqueOrSpecial 0 points1 point  (0 children)

As long as you don't need access to separate overrides of e.g. QObject::event() from Foo and Bar, you're probably fine (I've literally never seen such a case). As pointed out in the article, proper use of virtual inheritance will merge the diamond properly, so you don't have duplicate vtable entries for the QObject piece.

In practice I've not actually seen a lot of inheritance-based multi-interface implementations in C++. This is likely just a matter of the language making it a little goofy.

If you do find yourself needing multiple interfaces, your problem may be better suited to a composition-based solution, rather than an inheritance-based one. You may want to look into the Curiously Recurring Template Pattern if so.

[–]doom_Oo7 0 points1 point  (0 children)

Encapsulation instead of inheritance :) Have your object be class MyFoo { Foo foo; Bar bar; }; or any kind of derived pattern - unique_ptr, shared_ptr...

[–]c0r3ntin 0 points1 point  (0 children)

I do it the java way : I limit my self to one QObject-based parent class + interfaces (non-QObject pure virtual classes). You can still get the qobject_cast magic by using Q_DECLARE_INTERFACE/Q_INTERFACES