QT pimpl inheritance from QObject - qt

While going through Qt code I had this basic question on the pimpl implementation.
As an example taking QWidget implementation.
QWidget ---inherits---> QObject
| |
contains contains
| |
\ / \ /
QWidgetPrivate ---inherits---> QObjectPrivate
Now QWidget has two instances of QObjectPrivate (through inheritance and through containment).
Why was the implementation done in this way? Isn't it an overhead to have two instances of the same object?

There aren't two instances of QObjectPrivate when instantiating a QWidget. If you look closely at the header file for QObject, you'll notice a protected constructor:
protected:
QObject(QObjectPrivate &dd, QObject *parent = 0);
Which sets the instance of QObjectPrivate to that passed in via the protected constructor:
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
This is the constructor called by all of the different QWidget constructors. The QWidget constructor passes in an instace of QWidgetPrivate which, as you noted, is a subclass of QObjectPrivate. Thus, only one instance of QObjectPrivate exists in QWidget.
Here's the default QWidget constructor that illustrates this:
QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
: QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
QT_TRY {
d_func()->init(parent, f);
} QT_CATCH(...) {
QWidgetExceptionCleaner::cleanup(this, d_func());
QT_RETHROW;
}
}

Related

How to use Q_DECLARE_METATYPE on QGraphicsitem derived class?

I want to use my objects as QVariants and for queued connections. Therefore I want to use Q_DECLARE_METATYPE(My_Item) and from the documentation I learned that I need a public copy constructor. I tried to write one, but I failed. Than I did read this copy constructor of derived QT class and the answer by BЈовић. From there I understand that what I intended to do is not going to work. What do I have to do make my objects useable for the Metatypesystem?
My_Item is based on My_Super_Item, which look like this:
class My_Item: public My_Super_Item {
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
explicit My_Item(Application *a, QString astring);
...
}
and
class My_Super_Item : public QObject, public virtual QGraphicsItem {
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
My_Super_Item(My_Application *a, QString astring);
...
}

How to catch a signal emitted from derived c++ class in QML?

My model is in C++ and front end is QML. The model consist of an interface class which contain other components. In simplied form (proof of concept stage) This interface class is pure virtual class called Base which is derived from QObject. I have a Derived class derived from Base
I am emitting signal in the derived class when data changes. My problem is how to catch this signal and process in QML?
derived.obj:-1: error: LNK2019: unresolved external symbol "public: void __thiscall Derived::somethingChanged(void)" (?somethingChanged#Derived##QAEXXZ) referenced in function "public: virtual void __thiscall Derived::doSomething(void)" (?doSomething#Derived##UAEXXZ)
My Base.h class is:
#include <QObject>
class Base : public QObject
{
Q_OBJECT
public:
explicit Base(QObject *parent = 0);
~Base();
virtual void doSomething() = 0;
signals:
public slots:
};
Derived.h is
#include "base.h"
class Derived : public Base
{
Q_OBJECT
public:
Derived();
~Derived();
virtual void doSomething();
signals:
void somethingChanged();
};
Derived.cpp is
#include "derived.h"
#include <QDebug>
Derived::Derived()
{
}
Derived::~Derived()
{
}
void Derived::doSomething()
{
qDebug() << "doSomething() called in Derived";
emit somethingChanged(); // this doesn't compile!
}
Connections {
target: What? // what should I put here,
onSomethingChanged: console.log("The application data changed!")
}
Again the problem is what do I put for target property? The model will only expose the interface class to qml which is the Base class but the signal is actually emitted in derived class. Should the signal be also virtual by any chance? How should I receive this signal in QML?
The MOC is the one who implements the function (your signal) void somethingChanged();.
An example could look like this in the moc_XYZ.cpp file.
// SIGNAL 13
void Derived::doSomething()
{
QMetaObject::activate(this, &staticMetaObject, 13, Q_NULLPTR);
}
So how do you make the MOC happy?
Add Q_OBJECT in your derived.h
In order to create interfaces to be used in Qt I have found two cases:
Based on QObject
This is the most easy form, and you are in the right way. Just create a class based on QObject with abstract methods and declare signals. Derived classes must not declare the signals again, just emit them when needed.
This is your case. MOC generator need to know that Base interface has an signal and it can be emitted. Just declare signals in Base instead derived classes.
Pure virtual class (extra info)
Sometimes you need to derive from any QObject-based class (e.g. QAbstractListModel) but it need to implement some interfaces too. C++ allows multiple inheritance, but Qt doesn't like classes that derive from two or more QObject-based classes.
So you should create a plain pure virtual class, and declare signals as any other unimplemented method.
// Base
class Base
{
public:
Base();
virtual ~Base();
virtual void doSomething() = 0;
signals:
virtual void somethingChanged() = 0;
};
Now, derive from Base and declare the signal again:
// Derived
class Derived : public QObject, public Base
{
Q_OBJECT
public:
explicit Derived(QObject *parent = 0);
~Derived();
//Implmetations of Base methods
public:
void doSomething();
//Declaration of Base signals
signals:
void somethingChanged();
}

What is the delete sequence of QObject with default parent in Qt?

The Qt Doc says if a QObject has a parent, then when the parent is deleted, it will also delete all its children.
However, if I have multiple QObjects with the default parent (0), when will they be deleted?
And what will be the sequence of deleting?
If we're talking about pointers to QObject, no, they won't be deleted. You will have a memory leak unless you delete them manually so there won't be any sequence of deleting.
Pointers don't release their memory unless delete is called on them. Say you have a pointer to a memory location to which no other pointer points. If that pointer goes out of scope and you don't call delete on it, you will have a memory leak because if no other pointer points to that memory location then you won't have access to that memory location anymore. And you get an inaccessible and useless chunk of memory.
In classes, destructors have the purpose of releasing the memory when deleted. Destructors are called when instances of the classes go out of scope(in case of instances allocated on the stack i.e. static, e.g. MyClass x;) or when delete is called of them(in case of pointers i.e. dynamic, e.g. MyClass *x = new MyClass;)
Qt created a clever mechanism so that programmers won't have to think that much of these things because lots of errors occur because of them. So Qt introduced parents, i.e. if you set a QObject a parent, when you will delete the parent the QObject will be deleted as well.
If you use QObject pointers as members in a class and don't set them a parent, when an instance of that class gets deleted you will have a memory leak unless, of course, you delete them manually in the destructor.
For example the following implementation will create memory leak if used:
class MyObject : public QObject
{
public:
MyObject(QObject *parent = 0);
~MyObject();
private:
QTimer *m_pTimer;
}
MyObject::MyObject(QObject *parent) : QObject(parent)
{
m_pTimer = new QTimer; // memory leak when this will be destroyed
}
MyObject::~MyObject()
{
}
In order to fix this you should provide this as parent:
MyObject::MyObject(QObject *parent) : QObject(parent)
{
m_pTimer = new QTimer(this);
}
or
MyObject::~MyObject()
{
delete m_pTimer;
}
In an implementation like this:
class MyObject : public QObject
{
public:
MyObject(QObject *parent = 0);
~MyObject();
private:
QTimer m_timer;
}
MyObject::MyObject(QObject *parent) : QObject(parent)
{
// Do stuff
}
MyObject::~MyObject()
{
}
where you don't have pointers and memory allocated on the heap, all the members are destroyed when getting out of scope i.e. when the instance of the class(in our case MyObject) gets out of scope.
I consider worth mentioning here the layouts system in Qt.
Lets say you have a QWidget with a QPushButton inside it. If you create a QLayout, add the QPushButton to the QLayout and set the QLayout on the QWidget with QWidget::setLayout, automatically a child-parent relationship will be created between the QPushButton and the QWidget and also between the QLayout and the QWidget.
Here's an example:
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
QGridLayout *m_pLayout;
QPushButton *m_pButton;
};
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
m_pLayout = new QGridLayout;
m_pButton = new QPushButton;
m_pButton->setText("Push me!");
m_pLayout->addWidget(m_pButton, 0, 0);
setLayout(m_pLayout); // In this moment *this* will be automatically
// set as parent for both m_pLayout and m_pButton
// even though no parent was passed to their constructors.
}
Widget::~Widget()
{
}
I hope this helps.

connect QPushButton via lambda

I am trying to connect QPushButton to lambda expression:
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, [](){
qDebug()<<"clicked";
});
Compiler gives me an errors like: No matching function to call "MyClass::connect(..."
What I am doing wrong?
The connect function, which is part of Qt's signal and slots mechanism is Qt's extension to C++.
The connect function is actually a static function of QObject, so you can use it from anywhere, by simply including QObject: -
#include <QObject>
...
QObject::connect(itemPtr1, SIGNAL(someFunction()), itemPtr2, SLOT(someOtherFunction());
The objects itemPtr1 and itemPtr2 are pointers to instances of classes that are derived from QObject and support signals and slots.
In order for a class to use the signal and slot mechanism, it must inherit from QObject and declare the Q_OBJECT macro:-
class MyClass : public QObject
{
Q_OBJECT // the Q_OBJECT macro, which must be present for signals and slots
public:
MyClass(QObject* parent);
signals:
public slots:
private:
void StandardFunction();
};
As this class inherits QObject, it now has direct access to the connect function, allowing calling connect directly:-
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, []()
{
qDebug()<<"clicked";
});
Finally, Qt 5 introduced a new syntax for signals and slots: -
connect(loadTextFileButton, &QPushButton::clicked, this, &MyClass::StandardFunction);
You may have noticed that the advantage here is that the signal can be connected to a function that is not declared as a slot. In addition, using this syntax provides compile time error checking.

SIGSEGV with QMainWindow singleton

The application I am writting as unique instantiation of some classes which have to be accessible easily. For that i use singletons.
For exemple my Core is defined as :
class Core : public QObject
{
Q_OBJECT
public:
Core();
~Core();
static Core& getCore()
{
static Core mycore;
return mycore;
}
(...)
};
and it works just great. However I tried to do the same with my MainWindow class, which interits from QMainWindow. I need that in order to access methods such as geometry() from other objects
However Core works great, MainWindow makes error when clossing the programe. The main window destructor is called and executed apparently once ( debug using qDebug() ) but i still have a SIGSEGV signal. What's happening? How to solve it?
Here is the code of MainWindow
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow& getUi()
{
static MainWindow myUi;
return myUi;
}
public slots:
void refreshImage();
private:
Ui::MainWindow *ui;
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(&appCore(), SIGNAL(refreshed()), this, SLOT(refreshImage()));
}
MainWindow::~MainWindow()
{
delete ui;
}
And the main code
QApplication app(argc, argv);
try
{
appCore().setDevice(MDMA::Kinect);
appUi().show();
return app.exec();
} catch(MDMA::exn e) {
(...)
}
where appCore and appUi are macros for Core::getCore and MainWindow::getUi()
This crash probably results from your QApplication being destroyed before the MainWindow.
If you cannot pass your MainWindow via other ways to the code where it is needed (e.g. as argument or via QObjecg::parent()), you could employ a technique similar to what QApplication does with it's instance method (a non-owning global reference):
Construct your MainWindow as an ordinary local variable on the stack, after the QApplication. Then set a global pointer (maybe better a QPointer; e.g. a static member of MainWindow), which you initially initialize to 0, to this in the constructor of MainWindow. You can also check if it was already initialized here to enforce the uniqueness. Via a public accessor method (instance?) for the global pointer, you can access the class from everywhere while ensuring destruction before QApplication.
If you want to make singletone, try to use general technics, for example, as described here:
http://www.qtcentre.org/wiki/index.php?title=Singleton_pattern
Hope, lot of questions will dissappear after reading all of that article.
As for me, there is nice and simple realization of singletone.
Good luck!

Resources