Qt: inheritance cause ambiguous - c++

I have the following case:
class A: public QObject
class B: public A, public QThread
Then the inheritance ambiguous happens because the QObject is inherited twice...
Is there a solution to this?

QThread inherits non-virtually from QObject. Therefore, there is no way of inheriting down an hierarchy from both QThread and QObject without creating an ambiguity. Virtual inheritance won't help here, since you are not dealing with any diamond inheritance pattern.
A fix is to alter your design, as #Gabor Angyal mentioned.
Related question: how can i inherit from both QWidget and QThread?

Multiple inheritance of QObject base classes does not work.
You can do something like this to solve this:
class A: public QObject
class B: public A
{
Q_OBJECT
public:
//...
QThread *threadController() { return &mThreadController; }
private:
//...
QThread mThreadController;
}
You could also write delegates for the signals and slots you need instead of exposing the whole QThread object, or just write higher level API for class B and leave its internal QThread completely hidden. Depends on what you are trying to do, really.
If you really need to subclass QThread, then just use that as member variable type instead.

A little tricky, but might work for you:
template<class T>
class A: public T
class B: public A<QThread>
And if you need to use A just by itself then:
A<QObject> *a = new A<QObject>;
This pattern is called Mixin.
UPDATE
Ok, I realised that the moc system would obviously not work with this solution. I support hyde's answer instead.

Related

Qt Multiple-inheritance goes wrong

I a project of mine, written in Qt, I have a QWidget Widget that should display either a MyTreeWidget (inheriting from QTreeWidget) or a MyTableWidget (inheriting from QTableWidget)
Constraints
Widget shouldn't know who it is talking to. Therefore it must (??) own a class inherited by the My(Tree|Table)Widget
MyTreeWidget and MyTableWidget share a lot of code and I don't want to copy paste this code. So I thought of making them inherit from a MyGenericView which inherit from QAbstractItemView
The Interfaces
#include <QAbstractItemView>
#include <QTreeWidget>
#include <QTableWidget>
class MyGenericView : public QAbstractItemView
{
Q_OBJECT
public:
MyGenericView();
};
class MyTreeWidget : virtual public QTreeWidget,
virtual public MyGenericView
{
Q_OBJECT
public:
explicit MyTreeWidget(QWidget *parent = 0);
};
class MyTableWidget : public MyGenericView, public QTableWidget { ... };
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0) :
QWidget(parent)
{
m_genericView = new MyTreeWidget();
}
private:
MyGenericView *m_genericView;
};
The Error
erreur : invalid new-expression of abstract class type 'MyTableWidget'
m_genericView = new MyTableWidget();
note: because the following virtual functions are pure within 'MyTableWidget':
class MyTableWidget : public QTableWidget, public MyGenericView
And the same for MyTreeWidget.
So how would you correct this?
It seems that what you're trying to do is ill-advised. Both views that you derive from are convenience views. They hopelessly mix up the view with the model. It's OK to use them if the needs are simple and convenience is all you're after, but in your case I presume most of the shared code is related to the model side of things, not to the view. You could probably achieve what you wish by simply showing a QStandardItemModel on either a stock QTableView or a stock QTreeView, and having a class that uses the QStandardItemModel to build up your data structure.
For more details of how you could do it, if it turned out to be the right thing to do, see this answer.
Edit : As suggested below in comments, this answer is based on faulty assumptions. Please see the better answer below.
First, you have an issue of diamond inheritance. Your error is because MyTableWidget has an undefined pure virtual member function.
Frankly though, I'm not sure why you want to use multiple inheritance at all here. If it's to save on code duplication, why can't MyTreeWidget and MyTableWidget share behavioural elements via composition instead of inheritence? Is this definitely a case of is-a vs has-a? If it's code specific to widgets that is shared but don't overlap in any way with the QTableWidget/QTreeWidget approach, just write an adaptor class that will be filled with either a Tree or Table widget.

Why QObject needs to be the first in case of multiple inheritance

According to http://qt-project.org/doc/qt-4.8/moc.html#multiple-inheritance-requires-qobject-to-be-first the QObject must be the first in the base classes when using multiple inheritance.
Is this because of some limitation in the moc tool or C++ memory layout problems are taken into consideration too, thus this restriction came into existence?
Assume that we have a class Test declared as:
class Test : public Foo, public QObject
{
Q_OBJECT
[..]
};
If you take a look at the moc_test.cpp file that the moc tool has generated, you will see something like:
[..]
const QMetaObject Command::staticMetaObject = {
{ &Foo::staticMetaObject, qt_meta_stringdata_Command,
qt_meta_data_Command, &staticMetaObjectExtraData }
};
[..]
Compiler will complain about staticMetaObject not being the member of Foo, as Foo is not a QObject. For some reason the moc tool generates this code taking the first parent class. Thus if you declare Test as:
class Test : public QObject, public Foo {};
The generated code will look fine to compiler.
I think this is made just for convenience because moc tool will hardly know which of the parent classes is a QObject without parsing the whole hierarchy.
Note: If you don't use the Q_OBJECT macro, you can derive your class from others in any order.

Can't access C++ QObject subclass methods from QML

Yesterday I was asked to recreate a regular QT form using QML (which was my first attempt ever using QLM). Everything was going well until I tried using c++ methods in the QML. This is obviously not the original code, but the scenario looks something like this:
I have a super class deriving from QObject, with some properties, methods and even virtual methods:
class SuperClass : public QObject {
Q_OBJECT
Q_PROPERTY(QString someProperty READ someProperty WRITE setSomeProperty)
protected:
QString m_someProperty;
public:
QString someProperty(void){return m_someProperty;} //get method
void setSomeProperty(QString newValue){m_someProperty = newValue;} //set method
Q_INVOKABLE virtual QString printSomething(void) = 0;
}
And then I have a class deriving from the SuperClass (like a specialization) with some more specific properties and methods and of course the virtual methods implementations and stuff:
class DerivedClass : public SuperClass {
Q_PROPERTY(QString someSpecificProperty READ someSpecificProperty WRITE setSomeSpecificProperty)
private:
QString m_someSpecificProperty;
public:
QString specificProperty(void){return m_someSpecificProperty;} //get method
void someSpecificProperty(QString newValue){m_someSpecificProperty = newValue;} //set method
QString printSomething(void){return QString("Something!");} //SuperClass virtual method
Q_INVOKABLE QString printSomethingSpecific(void){return QString("Something Specific!");}
}
OK, this is it! Now assuming that DerivedClass is instantiated and added to the QML context properly under the name of "DrvClass" for example and that I have some QML control like a TextField which has a 'text:' property:
text: DrvClass.someProperty
using MasterClass' properties, it works just fine.
text: DrvClass.printSomething()
even using virtual methods from MasterClass' which are implemented in the derived class works fine. but...
text: DrvClass.someSpecificProperty
doesn't work and I get something like "Unable to assign [undefined] to QString"
text: DrvClass.printSomethingSpecific()
also doesn't work! "TypeError: Property 'printSomethingSpecific' of object SuperClass() is not a function" And the weird part is that it says that it's not a function from the SuperClass, being the instantiated class the Derived one!
I've looked for similar errors, but most of the time is from people who just forgot to include the Q_OBJECT macro... Mine's there for sure!
It seems that QML doesn't like much classes deriving from other classes that derive from QObjects :-/ Probably something to do with the meta-object compiler who only looks for invokable methods where it finds the Q_OBJECT macro and not on it's subclasses!
So what you guys think the solution for this might be?
I could just add the Q_OBJECT macro to the DerivedClasses instead of the SuperClass, but I really need the SuperClass to be a QObject because of signals and stuff! So is there some other macro I have to add to the DerivedClass for the moc to 'see' it?
Or is this just the fruit of inexperience and I'm doing a dumb mistake somewhere?
DerivedClass is missing Q_OBJECT macro (it is not inherited!).
Then simply run qmake again on your project & compile: it should work.

Why is a QList not derived from a QObject?

I wanted to create a QObservableCollection wrapper around a QList(using an internal QList for implementation and forwarding all calls while emiting some sort of CollectionsChanged signal for functions that change the collection), but I see that QList does not inherit from QObject.
I believe you need to inherit from QObject to emit Qt Signals. So I'd need to inherit from QObject for my QObeservableCollection.
But QList and QVector and the other Qt collections doen't inherit from QObject, so I imagine their must be some sort of downside or problem making a collection.
I see that QSignalSpy inherits from both QObject and QList<QList<QVariant>> so maybe they just didn't see a reason to inherit from QObject?
There is a very important technical reason: The moc cannot handle templates, which is pretty much a necessity for a generic container type.
QList is meant to be a value type (like std::vector) which uses implicit sharing while QObjects must be used as pointers and disallow copying
there are other classes which mirror this use such as QImage
Reason is simple containers are like values, you have assign operator, you can copy them clone and so on.
QObjects can't have such functionality, they are not copyable. Try imagine what should happen when you creating clone of object with connected slots and signals. It will lead to total mess. And what should happen with children of cloned object? Should be also cloned?
Another thing is templates usage. Class template which is a QObject is real problem for moc a tool.
It is certainly not true that you need to be a QObject to emit signals. All you need is there to be a QObject somewhere that emits the signals for you. If you want your class to be directly passable to QObject::connect, your class should provide a conversion operator to QObject* that returns the pointer to such a proxy object. This completely sidesteps the whole no-templates-with-moc brouhaha.
class FrobinatorObject : public QObject {
Q_OBJECT
Q_SIGNAL void frobSignal();
...
};
template <typename T> class Frobinator {
QScopedPointer<FrobinatorObject> m_proxy;
// Could be a QSharedPointer, depending on what semantics we want
...
public:
operator FrobinatorObject*() const { return m_proxy.data(); }
};
...
Frobinator<int> frob;
QObject::connect(frob, SIGNAL(frobSignal()), ...);
// or
QObject::connect(frob, &FrobinatorObject::frobSignal, ...);
Also note that while it's true that you can't have signals nor slots in a template-parametrized class, you can certainly have them in a base class that you then derive from. The base class can deal with type-deleted arguments. So:
// This won't work
template <typename T> class TemplateClass : public QObject {
Q_OBJECT
Q_SLOT void aSlot(const T *);
...
};
// But this certainly does work
class BaseClass : public QObject {
Q_OBJECT
Q_SLOT void aSlot(const void *);
...
}
template <typename T> class TemplateClass : public BaseClass {
void aMethod(const T * t) {
BaseClass::aSlot((const void*)&t);
}
...
}
The TemplateClass can also dynamically add slots of the correct type signature to the BaseClass. While that requires some understanding of Qt's internals, it can certainly be done for a class that's supposed to be a reusable, framework-style class.
While I can't look into the minds of the developers, I would say that there's simply no need. A QList is a simple container. It should hold elements, allow for their addition or removal, iteration over them, etc.
It does not need a parent or children. There's no immediate need for signals or slots. It's a matter of keeping things simple.
If you do indeed require additional functionality beyond what a QList provides, it's easy enough to implement. But as for a general case, I guess it's a reasonable and logical decision to not overcomplicate things.
The extra overhead in inheriting from QObject is unnecessary for the majority of uses. Containers should be as small and as fast as possible.
If you wanted to inherit from QList and provide that functionality for a class of your own, you can do that.

Using Qt signals and slots with multiple inheritance

I have a class (MyClass) that inherits most of its functionality from a Qt built-in object (QGraphicsTextItem). QGraphicsTextItem inherits indirectly from QObject. MyClass also implements an interface, MyInterface.
class MyClass : public QGraphicsTextItem, public MyInterface
I need to be able to use connect and disconnect on MyInterface*. But it appears that connect and disconnect only work on QObject* instances. Since Qt does not support multiple inheritance from QObject-derived classes, I cannot derive MyInterface from QObject. (Nor would that make much sense for an interface anyway.)
There is a discussion of the problem online, but IMO the proposed solution is fairly useless in the common case (accessing an object through its interface), because you cannot connect the signals and slots from MyInterface* but must cast it to the derived-type. Since MyClass is one of many MyInterface-derived classes, this would necessitate "code-smelly" if-this-cast-to-this-else-if-that-cast-to-that statements and defeats the purpose of the interface.
Is there a good solution to this limitation?
UPDATE: I noticed that if I dynamic_cast a MyInterface* to QObject* (because I know all MyInterface-derived classes also inherit eventually from QObject, it seems to work. That is:
MyInterface *my_interface_instance = GetInstance();
connect(dynamic_cast<QObject*>(my_interface_instance), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));
But this really seems like I am asking for undefined behavior....
You found the answer yourself: the dynamic_cast works as you would expect. It is not undefined behavior. If the instance of MyInterface you got is not a QObject, the cast will return null and you can guard yourself against that (which won't happen, since you said all instances of the interface are also QObjects). Remember, however, that you need RTTI turned on for it to work.
I would also offer a few other suggestions:
Use the Q_INTERFACES feature (it's not only for plug-ins). Then you'd work in terms of QObject and query for MyInterface using qobject_cast when it is really needed. I don't know your problem in detail, but since you know that all MyInterface instances are also QObjects, this seems to be the most sensible approach.
Add a QObject* asQObject() abstract method to MyInterface and implement it as { return this; } in all subclasses.
Having a QGraphicsTextItem (composition) instead of being one (inheritance).
You can declare MyInterface that takes a QObject in its constructor:
class MyInterface {
public:
MyInterface(QObject * object);
QObject * object() { return m_object; }
...
private:
QObject * m_object;
};
MyInterface::MyInterface(QObject * object) :
m_object(object)
{
...
}
Then in MyClass constructor:
MyClass::MyClass() :
MyInterface(this)
{
...
}
And you can connect the signal:
MyInterface *my_interface_instance = GetInstance();
connect(my_interface_instance->object(), SIGNAL(MyInterfaceSignal()), this, SLOT(TempSlot()));