elgolondrino
elgolondrino

Reputation: 665

Error while inheriting QObject

I've got a class applicationManager that ought to emit signal when there is an info message or an error occurs, while I'm suppose to log that messages consuming it by QXmppLogger class object. There is a QXmppLoggable class that got methods like info() and warning() that emits a signal logmessage() of internal QXmppLogger. So, in order to emit a signal I've inherited QXmppLogable class which inherits QObject itself, hence to be able to use info() and warning() and connected emitted SIGNAL(logmessage()) by info() and warning() methods, to SLOT (log()) of QXmppLogger object. Here is the code snippet:

header "imApplicationManager.h"

class applicationManagement: public QXmppLoggable
{
    //Q_OBJECT
public:
    bool createDataBaseConnection();
    applicationManagement();
    ~applicationManagement();
    void setLogger(QXmppLogger *logger);
private:
    QXmppLogger *logger;
};

and related "imApplicationManager.cpp"

applicationManagement::applicationManagement()
{
   QObject::connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)),
                    logger, SLOT(log(QXmppLogger::MessageType,QString)));
}

applicationManagement::~applicationManagement()
{
    // db..closing
}

bool applicationManagement::createDataBaseConnection(){

    //...database conncetion...

    if (!dataBase.open()){
        warning(QString("Cannot open database %1").arg(dataBase.lastError().text()));
        qDebug()<< "Cannot open database " << dataBase.lastError();
      return false;
    }
    info(QString("Database succeeded!"));
  return true;
}

void applicationManagement::setLogger(QXmppLogger *logger)
{
    if(this->logger != logger)
        this->logger = logger;
}

in the main.cpp

#include "imApplicationManager"
#incLude "QXmppLogger"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    applicationManagement aa;

    QXmppLogger log;

    aa.setLogger(&log);   

    return a.exec();
}

Compilation informs of no error but when luanched there is a Sigmentation fault. How can I fix that?

Upvotes: 0

Views: 1424

Answers (3)

dtech
dtech

Reputation: 49279

OK, decided to post a full answer:

  • First of all, you do NEED the Q_OBJECT macro. The errors you get from it will likely disappear when you Clean All, Run qmake and Rebuild All from the Build menu of QtCreator. Qt relies on a LOT of generated boilerplate code you never have to type, and without Q_OBJECTthat code will not be generated. That is the reason you sometimes need to clean up after you made changes, run qmake (which generates the code) and rebuild with the now up-to-date generated code.

  • Second - in the constructor of applicationManagement you connect to an uninitialized pointer logger. This is probably why you get segmentation fault. You can use two approaches to fix that:

    1. Pass the pointer to the logger in the constructor of applicationManagement, this way you have something to connect to in the constructor. This way you cannot instantiate an applicationManagement before a logger, unless you use logger(new QXmppLogger) in the constructor initialization list.

    2. Move the connection from the applicationManagement constructor to the setLogger()method. Do not forget to disconnect a previous connection if any.

Upvotes: 3

TheDarkKnight
TheDarkKnight

Reputation: 27611

It has been mentioned that the Q_OBJECT macro is needed, but I think a little explanation would be useful too, as understanding why it's needed helps to remember to use it.

Qt adds to C++, amongst other features, the functionality of signals and slots and this is done with the Meta-Object Compiler (or moc for short). When compiling Qt code, the moc parses the header files and creates source code for you, which can be seen in the moc files. Occasionally these get out of sync and cleaning these files will fix this issue.

If you look more closely at the Q_OBJECT macro, it is defined as this: -

#define Q_OBJECT \
public: \
    Q_OBJECT_CHECK \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    QT_TR_FUNCTIONS \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
private: \
    Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    struct QPrivateSignal {};

As can be seen here, the Q_OBJECT macro adds function definitions to the class and its the implementation of these in the QObject parent class that provides the added C++ features such as signals / slots, properties, RTTI etc. When calling signals and slots, internally Qt uses the qt_metacall function. There's an interesting explanation of the implementation of these here. Therefore without the Q_OBJECT macro in a class derived from QObject, signals and slots won't work.

Upvotes: 2

loentar
loentar

Reputation: 5239

You use logger but it is not initialized before:

   QObject::connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)),
                    logger, SLOT(log(QXmppLogger::MessageType,QString)));

try to rewrite your constructor like that:

applicationManagement::applicationManagement(QXmppLogger *logger_):
  logger(logger_)
{
   QObject::connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)),
                    logger, SLOT(log(QXmppLogger::MessageType,QString)));
}

or connect that signal after initializing logger.

Upvotes: 1

Related Questions