PDA

View Full Version : Multiple inheritance of QObjects



tescrin
7th January 2013, 23:09
I've been getting crafty, and it worked until I needed to multipally inherit (I realize that's not a word :p)

The craftyness is that I've abstracted a bunch of boilerplate code to base classes that mean any newb can create a class derived from them and they'll automatically hook up to the desired COM interface and all COM events will route their important information to a virtual function (that obv.s needs to be implemented by them to use said events.)

The problem with said craftiness is if I need to speak to multiple interfaces in COM I would either need to create new combinations of these interfaces for each possible combination (at least, that occurs) rather than simply inherit from both. It looks like this:



class A : public QWidget
{
Q_OBJECT
//..
}

class B: public QWidget
{
Q_OBJECT
//..
}

class C: public A, public B //doesn't work obviously
{
Q_OBJECT
//..
}


I'm having trouble finding online how you work around this; which IIRC is declaring something like:


class A : private QWidget
{
Q_OBJECT
//..
}

class B: private QWidget
{
Q_OBJECT
//..
}

class C: public A, public B //,public QWidget?
{
Q_OBJECT //<- I noticed some confusion in another thread about whether this was necessary
//..
}


but... this doesn't work (with or without the public QWidget; or at least, it has warnings either way.)



As to the inevitable "why are you doing this again..?" question: These base classes are Q_OBJECTs that take in another class and automatically hook up the COM event handler's released SIGNAL with their relevant SLOT, meaning that no code has to be written for a new class (when correctly inheriting) in order to listen to COM events relevant to your object. Were I to take out the Q_OBJECT declaration I would have to write the connection code each time in a manager class that handles these object's lifetimes, which is fine.. but it's less elegant and does require extra time needlessly.



So my fellow C++/Qt wizards, what should I do..? (I did look at the other multiple inheritance threads that popped up, but they didn't seem to address this specific problem; nor has google been kind this time around.)

Added after 34 minutes:

Ah, it looks like virtual inheritance (http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class#21607) is what I was looking for; though this still doesn't work with QWidget derivation as it complains when it hits .moc files that you're converting from a QObject* to a MyWidget* and that doing so virtually isn't possible.

Added after 23 minutes:

With some more research it would seem that the problem is untenable due to Qt not supporting virtual inheritance in moc and this being the Diamond Problem.

The solution I believe I'll be taking (for those who run across this in the future) looks like this:

-I have a Manager class that already hands these objects out (and manages their lifetimes, etc..)
-because the Manager has all of the objects that need these signals and I wish to not have to change code when adding more of these objects; but these are the ONLY Qt objects it holds, I can utilize it's child list to walk through and cast each of these object's pointers to the type of object I need and simply deliver the "signals" manually. Another option would be to change the derived class's version of the virtual function to a slot (though I am only *assuming* that that would work.)

amleto
7th January 2013, 23:57
First question - do you really need QWidgets? Or just QObjects?

Comment: Just making the inheritance private will not work + is not correct. You need to use virtual inheritance to resolve 'the dreaded diamond'.

Since Qt doesn't like this (apparently) then you could perhaps get around it by doing something like this:


// A interface
class IA
{
// methods in A
};

class A : public IA, public QWidget
{
// your implementations
};

// B interface
class IB
{
// methods in A
};

class B : public IB, public QWidget
{
// your implementations
};

class IC : public IA, public IB
{
};


class C : public IC, public QWidget
{
public:
// IB is implemented by b
// IA is implemented by a

// e.g.
/*
void foo_a() {a.foo_a();}
void foo_b() {b.foo_b();}
*/

private:
A a;
B b;
};