Search code examples
c++qtinner-classesnested-class

Inner classes in Qt


I am using Qt5 with the VS2013 compiler. I am trying to nest two classes CUDial and DUDial in the same outer class UDial.

UDial is a QDialog type class. I would like CUDial and DUDial to be both of QWidget type. It for use with a QTabWidget variable in the outer class.

So, I write the code as follow:

class UDial : public QDialog
{
    Q_OBJECT

    class CUDial : public QWidget
    {
        Q_OBJECT

        // Some variables

     public:

        CUDial(QWidget *parent = 0);
    }wid1;

   class DUDial : public QWidget
   {
        Q_OBJECT

        // Some variables

    public:

        DUDial(QWidget *parent = 0);
   }wid2;

   QTabWidget *tab;
   QDialogButtonBox *box;
   QVBoxLayout *vlay;

public:

   UDial(QWidget *parent = 0);
};

After I implemented the code, I tried to compiled and got the following C2664 error:

error: C2664: 'int QTabWidget::addTab(QWidget *,const QIcon &,const QString &)' : cannot convert argument 1 from 'UDial::CUDial' to 'QWidget *'

No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

I guess that it is a problem with the QWidget inheritance of my nested classes.

Is there a way I can solve that issue?


Solution

  • After some discussions in the comments I admit the approach I encourage here is a bit opinion based, so I strongly advise to read all answers under this question. However, please do note the paragraph with statements in bold in this answer.


    In general, following Qt's suggestion from the documentation:

    QObjects organize themselves in object trees. 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. It turns out that this approach fits the needs of GUI objects very well. For example, a QShortcut (keyboard shortcut) is a child of the relevant window, so when the user closes that window, the shortcut is deleted too.

    you should not hold instances of QWidget types by value, because when adding them to QTabWidget it will become their parent and will attempt to delete them on deconstruction.

    The problem lies in the fact that you are passing an object by value (wid1) to a function which requires a pointer (QTabWidget::addTab). Usually you can just change it to &wid1 but it can cause problems in the aforementioned context of Qt's memory management.

    In your particular case, it will work fine, because the destruction will start in your class, deleting its members, and they will correctly unregister from QTabWidget, so it won't attempt to delete them again later.

    This however can lead to an inflexible code structure - as explained in the linked page of Qt's documentation, where simple reordering of object construction leads to a crash.

    Also, you will need to manually reorder the members inside your class, to follow their dependencies as your code evolves. This seems silly, if you don't have to do it: Qt will do just fine managing the life-time of your widgets, and you don't have to worry about it.

    Thus, the safest solution is to have a pointer CUDial* wid1, allocate it with new and let QTabWidget manage its life-time.