Should I define a destructor for a derivate of QWidget - c++

I would like to know if I should define a destructor of a derivate of QWidget.
Example
class CustomWidget : public QWidget{
QLabel* field;
CustomWidget(QWidget* parent) :
QWidget( parent ),
field( new QLabel(this) ) {};
}
I've already read about the "Widget tree" that will call the destructor of all the child if the parent is destructed, but i mean, just to be sure

For the given one, no. The parenting system will take care of field. But u should add Q_OBJECT macro.

Related

Ownership of memory in user-defined classes deriving from Qt classes

I know that, in Qt, parent object takes ownership of its child objects. However, if I have my own class deriving from a Qt class, do I need to control memory in my derived-class' destructor or does Qt do it for me? Below is an example:
#include <QWidget>
#include <QPushButton>
class MyWidget: public QWidget{
public:
MyWidget(QWidget* parent = 0): QWidget(parent) {
this->setAttribute(Qt::WA_DeleteOnClose);
m_button = new QPushButton(this);
}
~MyWidget() { delete m_button; } // do I need this to prevent leaks?
private:
QPushButton* m_button;
}
So my question is, do I need ~MyWidget() to prevent memory leaks? Or would QWidget somehow manage the memory for me?
No you don't, QObject handles that. Everything derived will be collected as long as it is in a parent-children tree. QWidget inherits QObject and you inherit QWidget. So you are all set.
Note that there are still many Qt types which do not inherit QObject. Better look at the doc to be sure.

In Qt MainWindow, why does an instance have a pointer to an instance?

The MainWindow code generated by QtCreator says:
namespace Ui {
class MainWindow; // forward-declare Ui::MainWindow (?)
}
class MainWindow : public QMainWindow // Declare MainWindow class (Ui::MainWindow?)
{
Q_OBJECT
public:
explicit MainWindow( QWidget *parent = 0 );
/**/ ~MainWindow( void );
// ...
private:
Ui::MainWindow *ui;
// ...
};
main() does:
MainWindow w;
w.show( );
MainWindow::MainWindow( QWidget *parent ) does:
ui( new Ui::MainWindow ) // Initialization
I don't understand why a MainWindow instance has a pointer to another/a different/a new MainWindow in its ui instance variable. I instrumented the MainWindow::MainWindow constructor, and I can see it's only being called once. So presumably that's the automatic variable on the stack in main(). But what about the ui( new Ui::MainWindow ) that happens in the constructor? That's creating a MainWindow on the heap, isn't it? How is it being initialized?
Maybe the subsequent ui->setupUi( this ) in the constructor is doing some magic? Otherwise, it seems like this would recurse to stack crash, as each new MainWindow creates a new MainWindow to populate its ui instance variable.
The Ui::MainWindow class is code generated by uic from the respective QtDesigner file.
It is not a widget but a helper that contains code to populate a widget.
So in your case it is code that is used to populate a QMainWindow derived class named MainWindow.
Ui::MainWindow is held as a pointer to allow forward declaration and avoid build dependencies of code including MainWindow's header to the generate code (which will change everytime you change something in QtDesigner)
There are two different classes in play here:
::MainWindow
::Ui::MainWindow
I wouldn't go so far as to say they are not related - but they are not the same class.

C++ Qt base class virtual destructor

Do we need a virtual destructor for a classes which are gonna be used in Qt-way: set QObject-parent which will call in QObject's destructor deleteLater() or something like that for any object for which it was set as parent?
For example:
class MyWidget : public QWidget {
public:
MyWidget() {
w = new QWidget(this);
// "w" will be deleted automatically by parent MyWidget::QWidget::QObject's destructor afaik
}
private:
QWidget *w;
}
Do we need a virtual destructor for MyWidget class if it is gonna be inherited? I see no reason for this because it does not delete anything and each property of the class which is derived from QObject will be deleted from MyWidget::QWidget::QObject's destructor.
It doesn't matter if you add it or not as QObject inherited by QWidget has a virtual destructor, and this is propagated through the whole hierarchy.
You don't need to explicitly write an (empty) virtual destructor because QWidget already marks its distructor as virtual, so automatically all destructors of the class hierarchy are virtual.
But in general, if you write a class that is going to be inherited (and doesn't already have a base class with a virtual destructor), always specify a virtual destructor, otherwise things will blow up badly if anyone tries to destroy an object of your class hierarchy through a pointer of the base class type.

Copying classes derived from QGraphicsItem using memcpy does not creat new object

I have several different classes derived from QGraphicsItem or its children (like QGraphicsRectItem). I am at the point when I need to copy selected objects of those classes while not knowing exactly which one I copy.
Since QGraphicsScene::selectedItems() return a list of selected items I decided to use it, however I cannot copy the QGraphicsItem since its an abstract class. To address this I am trying to copy the object using malloc and memcpy.
MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene();
item = new QGraphicsRectItem(50,50,50,50);
item->setFlag(QGraphicsItem::ItemIsSelectable);
scene->addItem(item);
item->setSelected(true);
ui->graphicsView->setScene(scene);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
for(QGraphicsItem *item : scene->selectedItems())
{
QGraphicsItem *copiedItem=(QGraphicsItem *)malloc(sizeof(*item));
memcpy(copiedItem, item, sizeof(*copiedItem));
copiedItem->moveBy(50, 50);
scene->addItem(copiedItem);
qDebug() << item;
qDebug() << copiedItem;
}
}
MainWindow.h
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QGraphicsScene *scene;
QGraphicsRectItem *item;
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
};
GUI consisting of QGraphicsView and QPushButton is sufficient for this example.
This code seem to work, item and copiedItem have different addresses but the same properties as qDebug() returns.
The scene however return the following error:
QGraphicsScene::addItem: item has already been added to this scene
I don't quite understand why the scene thinks the items are the same while they have different addresses. Is there any way to solve this issue?
EDIT:
If possible I would like to do this without modifying the code of classes derived from QGraphicsItem, since this is a group work and I would not like to bug other functionalities.
If you look at the class definition inside qgraphicsitem.h, you'll see the following:
private:
Q_DISABLE_COPY(QGraphicsItem)
Q_DECLARE_PRIVATE(QGraphicsItem)
What this means is that, by design, you are not supposed to copy a QGraphicsItem, each object is supposed to be unique.
EDIT:
I would imagine that the reason that you are denied the copying ability is because QGraphicsItem follows the Composite Design Pattern. Creating a copy of a single object that has child items would result in child items having more than one parent. To get round that, you'd have to not only copy the item you're interested in but every child in the child hierarchy as well. For very large hierarchies, this can become a very time-consuming operation.
If you really feel that you need to make copies, you can create a cloning factory function/class that creates a clone of the QGraphicsItem and all it's children by going through all the object's properties and transferring them to a newly created QGraphicsItem.
If this is not feasible, perhaps think about accomplishing your goal in a different way.
You really want to be using the copy constructor or the assignment operator, not malloc and memcpy. This is how you copy objects in C++:
QGraphicsItem copiedItem = *item;
The problem of copying a class by block copying its memory with malloc is that if the class contains pointers to objects or arrays, then only a shallow copy will occur.
In your case of getting pointers to a QGraphicsItem, you'll need to identify the type of item you're copying (its actual child class, not base class) and use the copy constructor. QGraphicsItem includes a function called type(), which returns an int that indicates which item it is. You can also add to this in your own derived classes by implementing the type() function. For example, from the Qt docs: -
class CustomItem : public QGraphicsItem
{
...
enum { Type = UserType + 1 };
int type() const
{
// Enable the use of qgraphicsitem_cast with this item.
return Type;
}
...
};
Alternatively, if all the classes are your own type, you could use your own system.
Once you know the type, you can then copy the item with its copy constructor: -
// Example, assuming type denotes a QGraphicsItemRect
QGraphicsItemRect rect = (*originalRect);
Note that if you have inherited from QGraphicsItem and added members that are pointers, you'll need to add your own copy constructor to ensure a deep copy occurs, instead of a shallow copy.

C++ constructor and Qt

There is a statement in the foudations of Qt Development book that goes as follows:
MyClass::MyClass(const string& test, QObject *parent) : QObject( parent )
What is meant when we put : QObject( parent )?
Thanks.
Are you sure that there aren't two constructor declarations? The : QObject(parent) is an initializer list; it is initializing the base class QObject with the QObject::QObject(QObject*) constructor.
In short this means that MyClass inherits properties (and methods) from QObject
http://www.cplusplus.com/doc/tutorial/inheritance/
http://www.anyexample.com/programming/cplusplus/cplusplus_inheritance_example.xml
So MyClass is a QObject
When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is.
Reference