Qt: Inherit QObject in parent and other QWidget subclass in child - c++

I am writing a series of custom classes for Qt. What I need is to have a base class that has few custom signals and slots, and children classes will have it. However, I do know that inheriting from the same classes will be thrown an error. I have read the documentation but only dictates that I need to include QObject if I wish to use Q_OBJECT macro. This is the following sample code that I intend to do:
class Base : public QObject
{
Q_OBJECT
base signals here
public base slots here
}
class Child : public QLabel, public Base
{
// Other codes here
}
Will it be possible this way? Since I only wish to use Qt to connect with all children inherits from the parent class.

Multiple inheritance from QObject will not work for several reasons.
(Moc-Compiler does not work correctly and QObject has member variables which makes mutliple inheritance unsafe).
You better work with composition instead of inheritance in case you want to provide the same behavious to several objects.

Related

Signal/Slot base-Class Multi inheritance

in my Qt multithread programm I want to implement a QObject-based baseclass, so that every class derived from it cann use its signals and slots (for example to throw an error).
I implemented MyQObject : public QObject{...}. But for classes that derive from QWidget I cannot multi inher from QWidget and MyQObject.
I can solve the problem by calling the slot directly by QMetaObject::invokeMethod(...), but i am interested if there would be another way to solve this problem.
Multiple inheritance with QObject can be done following these rules:
Only one of the parents class can be a QObject/QWidget
The QObject parent have to be the first parent in the initialization.
There's a trick that allows you to declare a signal like function in a non-qobject interface and then declaring it inheriting that interface using composition. Take a look to this post, it may be useful.

Strategy pattern Qt ambiguous base

For a school project we have to make a 'game', in this game we visualize a maze and find our way through it. This visualization has to be possible in two different ways, in our case a text-based visualization and a more fancy way.
We have to use Qt for this, we are using a QMainWindow with a QWidget in it, this widget will be one or the other visualization. Seeing that during the game we should be able to switch between visualizations, we use the Strategy Pattern, so made an interface (ViewInterface) and both visualizations implement this. Beside implementing ViewInterface, both visualizations inherit another class, in the text-based this is QPlainTextEdit (to have a QWidget with text) and in the Fancy this is QDialog. Probem here is that in my controller, I have a pointer to a ViewInterface which is used to fill the QWidet but to do this ViewInterface also has to inherit from QWidget, which causes this error: QObject is an ambiguous base of 'TerminalView'.
Since the switching between views can be done while playing the game, and update should be called only on the currently-active view, we can't pass the specific view to 'setWidget'.
Am I doing something wrong or how can I solve this? (I already thought about it but can't come with solutions).
The problem here is that you inherit QObject twice: first in ViewInterface hierarchy, second in QDialog hierarchy (diamond problem). Try using virtual inheritance for your FancyView and TextView classes (DOES NOT WORK, SINCE VIRTUAL INHERITANCE SHOULD BE USED IN ENTIRE HIERARCHY)
But there is another problem with your design: both QDialog and QPlainTextEdit inherit QWidget. To resolve this issue you may do the following:
Make ViewInterface abstract without inheriting from QObject. This abstract class will define the interface of your FancyView and TextView and may or may not implement some common logic.
Implement FancyView and TextView with multiple inheritance from QDialog and ViewInterface and from QPlainTextEdit and ViewInterface respectively.
This way you may not encounter any problems with ambiguous base class.
UPDATE:
Did not see your edit yet: indeed this would solve the issue, but
another problem rises: if I do this, I can't use a ViewInterface
pointer to set my QWidget. It is possible indeed, but in my opinion
this is not really clean
Well, that is a real problem. An obvious solution is not to use ViewInterface* instead of QWidget*. But this means that you need to change quite a lot of code and it may actually be not that great in your case.
With respect to the given comment, I propose another solution:
Inherit ViewInterface from QWidget (with all desired interface functions):
class ViewInterface: public QWidget {
Q_OBJECT
...
}
In ViewInterface constructor set layout to be used by widget and set it up:
ViewInterface::ViewInterface (QWidget* i_parent)
: QWidget (i_parent) {
auto layout {new QGridLayout (this)};
// Zeroed margins to make full fit.
layout->setContentsMargins (0, 0, 0, 0);
setLayout (layout);
}
In constructors of derived classes add specific widget to layout:
class FancyView : public ViewInterface {
Q_OBJECT
FancyView (QWidget* i_parent)
: ViewInterface (i_parent)
, dialog_widget_ {new QDialog (this)} {
layout->addWidget (dialog_widget_);
}
...
private:
QDialog* dialog_widget_;
}
Implement desired interface using target widget. If you want to process events, you may use QObject::eventFilter (). In this case you should set your FancyView object from the code above as event filter for dialog_widget_.
NOTE: In this case you can not use FancyView as QDialog. A workabound for this issue is proxy QDialog signals, slots and public functions and create yet another wrapper class FancyViewDialog, that works as proxy for the methods, signals and slots in FancyView. That is not a fantastic solution, but I do not see any other way around diamond problem that allows "is-a" relation between ViewInterface and QWidget.
An interface should be abstract with virtual methods and have no concrete base classes. ViewInterface should not inherit from QWidget. That fixes your problem.
Now there are at least two solutions to converting the ViewInterface instance to QWidget:
Template the users of ViewInterface and have them ensure that the concrete type used does in fact derive from QWidget. That will work if the type is there's no runtime polymorphism.
If there's runtime polymorphism, add a QWidget * widget() = 0 method to the interface, and implement it in the derived methods. It's trivial: QWidget * widget() override { return this; }.
The interface can have both signals and slots - they must be virtual methods, but they certainly will work. See e.g. this answer to get started with virtual signals.
If you want to share some code between the two concrete implementations of ViewInterface, you can have an additional class that derives from ViewInterface to provide the shared code. Both TerminalView and FancyView would derive from that class. The helper class could be parametrized on the base class type, to have it jump through less hoops to access the widget, e.g.: class TerminalView : ViewHelper<QPlainTextEdit> { ... };

Inheritance system leading to ambiguity in Qt

I want to create a inheritance system in one of my Qt applications where there is a QObject derived class "Abstract1" that implements two signals and its derived classes, most of which will be QWidget derived.
The problem is that, the way I'm doing, is leading to "error: 'QObject' is an ambiguous base of " errors. A research on SO revealed the reason for that: I'm including two instance of QObject, one coming from my "Abstract1" class and the other from "QWidget":
class MyNewClass : public Abstract1, public QWidget
My question: how can I avoid the problem but still maintain the structure I want? That is, pure QObject class with the signals and subclasses which include this one and are also QWidget derived?

Is it safe to use *virtual* multiple inheritance if QObject is being derived from DIRECTLY?

I understand that in general, multiple inheritance from QObject-derived classes (even virtual multiple inheritance) is not supported in Qt.
I understand the reason to be (I think) that even in the virtual inheritance case, the Qt classes do not themselves virtually inherit from QObject. For example, if you attempt to derive a class virtually from both QWidget and QThread, this is placing the virtual inheritance in an irrelevant place in the inheritance chain and you still wind up with two QObject instances.
I therefore think it is safe, and supported in Qt, to use virtual inheritance where the ONLY Qt class being derived from is QObject itself.
I have:
class Top : public QObject {};
class Left : public virtual Top {};
class Right : public virtual Top {};
class Bottom : public Left, public Right {}; // Is this safe, and supported by Qt?
Note that instances of Bottom truly have only one instance of Top (and hence only one instance of QObject), so it seems that the rationale for avoiding multiple inheritance in Qt (even virtual multiple inheritance) does not apply here.
The above construct nonetheless results in the Qt compiler warning Class Bottom inherits from two QObject subclasses Left and Right. This is not supported!.
Am I correct? Is it safe to ignore the Qt compiler warning in this specific scenario? Is the above construct, involving virtual multiple inheritance directly from QObject, safe and supported in Qt?
No, multiple inheritance from QObject is not supported by Qt in any way.
The problem is not with virtual inheritance, it's Qt's meta-object system. Each QObject base class has an associated QMetaObject which manages signals, slots, properties, etc, and each meta-object knows its parent QObject so e.g. signals which exist in parent classes can be handled. The Qt moc is not able to deal with multiple inheritance from QObject or any of its sub-classes.

What is the correct way of Multiple inheritance in Qt/C++?

In my Qt application, I have a base class as follow. I am using QObject because I want to use Signal-Slot mechanism in all derived classes.
class IRzPlugin : public QObject {
public:
virtual void registerMenu(QWidget*);
virtual void execute();
}
Then I have another class as follow. I need to extend from QWidget because I need to implement event handling methods in all derived classes (such as mouseMoveEvent(), keyPressEvent() and others).
class IRzLayeringPlugin : public IRzPlugin , public QWidget{
}
But compiler gives these the errors:
C:\svn\osaka3d\tags\iter08\prototype\osaka3d\rinzo\plugin\moc_IRzLayeringPlugin.cxx: In member function `virtual const QMetaObject* IRzLayeringPlugin::metaObject() const':
C:\svn\osaka3d\tags\iter08\prototype\osaka3d\rinzo\plugin\moc_IRzLayeringPlugin.cxx:51: error: `QObject' is an ambiguous base of `IRzLayeringPlugin'
C:\svn\osaka3d\tags\iter08\prototype\osaka3d\rinzo\plugin\moc_IRzLayeringPlugin.cxx:51: error: `QObject' is an ambiguous base of `IRzLayeringPlugin'
make[2]: *** [CMakeFiles/Rinzo.dir/plugin/moc_IRzLayeringPlugin.cxx.obj] Error 1
In the current incarnation, it isn't possible to use QObject in multiple inheritance paths for a derived class (like your IRzLayeringPlugin class). The only solution I've ever seen was to create an interface class without any QObject inheritence, but with functions that directly correspond to the QObject functions you want to use, then implement the bridge between the interface and your other QObject class inheritance in your specific class. It gets ugly fairly quickly.
There was a similar question today here.
Basically, two things are needed:
Adding Q_DECLARE_INTERFACE after the interface class declaration
Adding the interface to the Q_INTERFACES macro of the class
After this, qobject_cast will work with your interfaces.
If you'd like to use signals and slots from the interfaces, you are out of luck, because you can only do that with types that derive from QObject. But in this case, you would always get the 'QObject' is an ambiguous base of 'IRzLayeringPlugin' error.
In this case, #Caleb's idea is still the best.