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.
Related
The title of the question is not very clear, I'll try to explain better.
I'm using Qt and the windows I'm working with derive (directly or indirectly) from QWidget. My windows has to be treat uniformly, so that I can take a pointer to the currently active window and invoke methods on it not knowing the actual window class, for this reason all my windows derive from another class, let's call it "myScreen". So far so good.
Now I would like to handle in "myScreen" also the hiding and showing of a window, so that it's uniform. For example passing from a window to another may imply calling "hide()" on the current window and "show()" on the new window. Since "myScreen" and QWidget don't have any relationship, I must use dynamic_cast to cast the windows that I know derive from "myScreen" and "QWidget" inside "myScreen" methods, in order to call the functions of QWidget just mentioned.
I know that probably the best way could be having "myScreen" derive from QWidget and all of other windows derive from that, but my goal is to change as little as possible the existing code. I also tried using virtual inheritance, but this approach can't work because of the files generated automatically by the moc (see this link Cannot convert from pointer to base class to pointer to derived class).
By now I managed to ensure that a constructor of "myScreen" is called by a class that derives from QWidget:
struct isQWidget{
class QWidgetType{
QWidgetType(){}
friend struct isQWidget;
};
template<class T>
static QWidgetType isQwidgetType(const T&){
static_assert (std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
return QWidgetType();
}
};
Constructor declaration:
myScreen(myScreen& parentScreen, isQWidget::QWidgetType);
Constructor definition:
sigin::sigin(QWidget *parent, myScreen& si) :
QWidget(parent),
myScreen(si, isQWidget::isQwidgetType(*this)),
ui(new Ui::sigin)
{
ui->setupUi(this);
}
I would like to treat a pointer to myScreen as a pointer to QWidget inside "myScreen" compile-time, since I know I will always use something that derives from QWidget.
Any idea on how I can manage this problem?
I had something like this in mind
template <typename T>
myScreen::myScreen(T &parent)
{
static_assert(std::is_base_of<QWidget, T>::value, "Error: not a QWidget");
QWidget &parentQt = dynamic_cast<QWidget&>(parent); // guaranteed to succeed in runtime by the above
...
}
So for parent which does not inherit from QWidget that would be a compilation error, and which does would always cast successfully.
Is there any way to add & use a class in the QMap value?
I wanna use QMap<QString, Aclass> map; in Qt. and when I want to set it's value in a function, some errors appear:
C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore\qglobal.h:1043: error: 'QWidget& QWidget::operator=(const QWidget&)' is private
Class &operator=(const Class &) Q_DECL_EQ_DELETE;
^
ps: my container class is inherited from QWidget & is singleton.
#include "Aclass.h"
#include <QWidget>
class AmainClass : public QWidget
{
Q_OBJECT
public:
static AmainClass &getInstance();
void setApp(QString name, Aclass app);
private:
AmainClass(QWidget *parent = 0);
QMap<QString, Aclass> map;
};
and in .cpp:
void AmainClass::setApp(QString name, Aclass app)
{
map.insert(name, app);
}
edit: Aclass is another class that is inherited from QWidget.
All Qt Objects that are derivated from QObject cannot be copied, because the copy constructor is private. This is the error message. You could use a reference or a pointer to your object in the map
QMap<QString, Aclass&> map;
or
QMap<QString, Aclass*> map;
Then the set function should be
void setApp(QString name, Aclass& app){
map.insert(name, app);
}
When you use pointers just replace & with *
As per Qt documentation, QObject and classes derived from it do not support being copied: Qt's meta-object mechanism and similar infrastructure relies on pointers to QObjects remaining valid, which would not hold if they were copied or moved around. You therefore cannot store a QObject in a container by value. Use a smart pointer instead:
QMap<QString, std::unique_ptr<Aclass>> map;
The same applies to setApp as well, of course:
void AmainClass::setApp(QString name, std::unique_ptr<Aclass> app)
{
map.insert(name, std::move(app));
}
Using a std::unique_ptr assumes three things:
You are using a compiler which supports that part of C++11.
Your version of Qt is recent enough to support move semantics.
You intend map to be the sole owner of the Aclass objects.
Since this is 2016, 1 & 2 should really be true by now.
As for 3, you generally need to sort out ownership (a design decision) before you choose how to implement it (a coding decision). Based on your original example, I assume you want map to own the Aclass objects, hence my use of std::unique_ptr.
If you instead want to use a different ownership scheme (such as using Qt's parent-child ownership relationships), you'd use different storage. For the parent-child thing, a raw pointer (or perhaps QPointer) would be appropriate.
You can use std::reference_wrapper<Aclass> as a type for value.
Be aware anyway that you must guarantee for the lifetime of the referenced objects.
See the documentation for further details.
Otherwise, you can use smart pointers like std::unique_ptr<Aclass> or std::shared_ptr<Aclass>, so that lifetime will be automatically managed for you.
See here for further details about shared_ptr, here for unique_ptr.
Otherwise, far simpler, you can define the missed operator operator= for Aclass. How almost depends on your actual problem, I cannot even say if it's a viable solution.
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.
Here is my issue.
I'm creating my own GUI Api. All the Widgets are in a container which has add and remove functions. The widgets derive from a base widget class. Here is where I'm unsure. I would ideally like a flow like this:
user creates a (desired widget deriving from base class) pointer, the container allocates and manages resources, the user has a pointer to the widget and can make calls to it.
However, polymorphism makes this confusing. How could I get my container to create the right type of new? The issue here is that anyone can create a new widget (like SuperTextBoxWidget) which is why supplying a string and doing a switch would not solve this.
My other quick-fix alternative is to make the user responsible for doing the new, and providing the pointer to the container's add function. But this does not feel idiot proof to me, and it seems odd to have the user do the initial allocation, but then the container manages the rest including erasure.
What would be the best and cleanest way to go about this?
Thanks
just an idea of what I have so far:
class AguiWidgetContainer
{
std::vector<AguiWidgetBase*> widgets;
public:
AguiWidgetContainer(void);
~AguiWidgetContainer(void);
void handleEvent(ALLEGRO_EVENT* event);
int add(AguiWidgetBase *widget);
bool remove(int widgetId);
};
I can think of at least two ways to do this.
1. Provide a template version of add:
template<class T>
int add() {
widgets.push_back(new T);
}
2. Use a factory class:
You can have a base factory class that defines methods to allocate (and possibly also free) widgets. Your users then provide their own subclass of the factory that creates the correct type of widget. For example:
class AguiWidgetFactory {
AguiWidgetBase *createWidget() = 0;
};
class AguiSuperWidgetFactory : public AguiWidgetFactory {
AguiWidgetBase *createWidget() {
return new SuperTextBoxWidget();
}
};
Your add method then takes a factory object as input and uses it to create a new widget.
I would suggest borrowing from COM and making your base widget class a pure virtual interface which includes a function to destroy itself. Then implementers of your widget don't even all have to use the same allocator (important if you ever cross DLL boundaries).
EDIT: Example:
class IWidget
{
public:
virtual Size Measure() = 0;
virtual void Draw(Point) = 0;
//and so on
virtual void Release() = 0;
};
class TextBoxWidget : public IWidget
{
TextBoxWidget() {}
~TextBoxWidget() {}
public:
// implement IWidget functions, etc, etc
static TextBoxWidget* Create() { return new TextBoxWidget(); }
virtual void Release() { delete this; }
};
Now TextBoxWidget can only be created with TextBoxWidget::Create() and released with someTBW->Release(), and always uses new and delete inside the same DLL, guaranteeing that they match.
My other quick-fix alternative is to
make the user responsible for doing
the new, and providing the pointer to
the container's add function. But this
does not feel idiot proof to me, and
it seems odd to have the user do the
initial allocation, but then the
container manages the rest including
erasure.
Why does it feel odd to you?
If a container starts taking responsibility of allocating the objects to be contained, it violats SRP. I would recommend that you design your interfaces to accept pointers to Widget objects that are allocated by users. The container is only responsible for containing/storing/retreiving them.
The user also takes responsibility of deleting the allocated objects.
Most of STL containers work in this way.
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()));