Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Commonly used inheritance of QObject



  • Hello everyone,

    My question is: should every single class inherit QObject?

    I would like to describe it with an example. I am creating a class, which will govern the database models used in the application and expose only the models and necessary functions to the external classes (mainwindow).

    Here is the small example with class "database":

    Header:

    #ifndef DATABASE_H
    #define DATABASE_H
    
    #include <QSqlDatabase>
    #include <QSqlQuery>
    #include <QSqlRelationalTableModel>
    #include <QDir>
    #include <QObject>
    #include <QMessageBox>
    #include <memory>
    
    class database
    {
    public:
        database();
    
    private:
        void setupDatabaseModel();
    
    private:
        std::shared_ptr<QSqlRelationalTableModel> article_model_;
    };
    
    #endif // DATABASE_H
    

    Source file:

    #include "database.h"
    
    database::database()
    {
        setupDatabaseModel();
    }
    
    void database::setupDatabaseModel()
    {
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
        if (!QDir("shared").exists())
            QDir().mkdir("shared");
    
        db.setDatabaseName("shared\\database.dbs");
        if (!db.open()) {
            QMessageBox::critical(0, QObject::tr("Cannot open database"),
                                  QObject::tr("Unable to establish a database connection.\n"
                                     "This example needs SQLite support. Please read "
                                     "the Qt SQL driver documentation for information how "
                                     "to build it."), QMessageBox::Cancel);
            exit(EXIT_FAILURE);
        }
    
        if (!db.tables().contains(QLatin1String("article")))
        {
            QSqlQuery query;
            query.exec("create table article (id varchar(20) primary key, "
                       "article_name varchar(40))");
        }
    
        article_model_ = std::make_shared<QSqlRelationalTableModel>();
        article_model_->setTable("article");
        article_model_->select();
    }
    

    In this case in order to be sure that QSqlRelationalTableModel will be destroyed I am packing it into the shared_ptr, I guess this is done in the correct way. I could add all the delete calls in the destructor, but I would rather avoid this, as this is not the way for the modern C++. The problem here is that at the end the syntax highlighting, autocomplete, in-built help will not work if I am using the shared_ptr.

    Does it mean, that I should rather stick to the architecture which is closer to Qt with the QObject tree, which will make sure that all the objects will be destroyed properly? So that basically every class, which does use Qt object should be inherited at least from QObject? I just want to understand the design methods with Qt better.

    Maybe this example is a bit exaggurated, as it may be clear, that this class should be inherited from QObject to avoid some cumbersome techniques, but I just wanted to support my post with a working example.


  • Moderators

    @Jendker said in Commonly used inheritance of QObject:

    The problem here is that at the end the syntax highlighting, autocomplete, in-built help will not work if I am using the shared_ptr.

    Switch to clang code model. In Qt Creator, go to Help->Plugins and enable the clang code model. It should work better with std shared pointers.

    Does it mean, that I should rather stick to the architecture which is closer to Qt with the QObject tree, which will make sure that all the objects will be destroyed properly? So that basically every class, which does use Qt object should be inherited at least from QObject? I just want to understand the design methods with Qt better.

    No there is no need for that.

    You can use the parent-child system (and it's kind of required for building UIs in QtWidgets and QtQuick), but it's not a requirement.

    There are a lot of Qt classes which are not QObjects. Take QString, QByteArray, QGraphicsViewItem as examples.

    Maybe this example is a bit exaggurated, as it may be clear, that this class should be inherited from QObject to avoid some cumbersome techniques, but I just wanted to support my post with a working example.

    Basically, use QObject:

    • for UI classes
    • when you need signals, slots, Q_PROPERTY etc,
    • when you want parent-child system to automatically clean things up for you
    • when using QThread with worker objects (just because it's super convenient and very easy to avoid synchronization problems)

    In other cases, you're fine with shared_ptr, QSharedPointer, QPointer and friends.



  • Thank you very much! The clang code model also works really nicely, the warnings are a nice additional help, thank you for the tip!

    My last question would be, is there any drawback of using the QObject inherited classes? Is there any reason to avoid it? I guess no, but I am asking to have a clear picture.


  • Moderators

    @Jendker said in Commonly used inheritance of QObject:

    My last question would be, is there any drawback of using the QObject inherited classes? Is there any reason to avoid it? I guess no, but I am asking to have a clear picture.

    Yes, there are drawbacks, although they are not severe in most cases:

    • QObjects can't be copied (copy constructor is private)
    • QObjects introduce overhead (meta-object info + the whole class do weight a fair bit https://doc.qt.io/qt-5/qobject.html)
    • some restrictions in multiple inheritance (you can't inherit from QObject twice, you have to place QObject as first class when using multiple inheritance. Or last, I never remember this ;) )
    • QObjects cannot be template classes (although this is pretty easy to work around)

    That's it, out of the top of my head. Not really hardcore drawbacks, they are more like corner-cases.



  • @sierdzio Thank you!


Log in to reply