继承QObject时出错

时间:2013-08-20 09:09:42

标签: qt

我有一个类applicationManager,当有信息消息或发生错误时应该发出信号,而我想要记录QXmppLogger类对象消耗它的消息。有一个QXmppLoggable类,它使info()warning()等方法发出内部QXmppLogger的信号logmessage()。因此,为了发出信号,我继承了继承QObject本身的QXmppLogable类,因此能够使用info()warning()并通过信息连接发出的SIGNAL(logmessage())( )和warning()方法,到QXmppLogger对象的SLOT(log())。以下是代码段:

标题"imApplicationManager.h"

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

和相关的"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;
}
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();
}

编译通知没有错误但是当luanched存在Sigmentation错误。 我该如何解决这个问题?

3 个答案:

答案 0 :(得分:3)

好的,决定发表一个完整的答案:

  • 首先,您需要Q_OBJECT宏。当您从QtCreator的Clean All菜单中Run qmakeRebuild AllBuild时,您从中获得的错误可能会消失。 Qt依赖于您不必键入的大量生成的样板代码,并且没有Q_OBJECT代码将不会生成。这就是您在进行更改后有时需要清理的原因,运行qmake(生成代码)并使用现在最新生成的代码重建。

  • 第二 - 在applicationManagement的构造函数中,您连接到未初始化的指针记录器。这可能是您获得分段错误的原因。您可以使用两种方法来解决这个问题:

    1. 将指针传递给applicationManagement构造函数中的记录器,这样就可以在构造函数中连接到某些内容。这样,除非在构造函数初始化列表中使用applicationManagement,否则无法在记录器之前实例化logger(new QXmppLogger)

    2. 将连接从applicationManagement构造函数移动到setLogger()方法。如果有的话,请不要忘记断开先前的连接。

答案 1 :(得分:1)

您使用的是记录器,但在以前未初始化:

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

尝试重写你的构造函数:

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

或在初始化记录器后连接该信号。

答案 2 :(得分:1)

有人提到需要Q_OBJECT宏,但我认为一点解释也是有用的,因为理解为什么它需要有助于记住使用它。

除了其他功能之外,Qt还增加了信号和插槽的功能,这是通过元对象编译器(或简称moc)完成的。在编译Qt代码时,moc会解析头文件并为您创建源代码,这可以在moc文件中看到。有时这些文件不同步并清理这些文件将解决此问题。

如果你仔细观察Q_OBJECT宏,它的定义如下: -

#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 {};

从这里可以看出, Q_OBJECT 宏将函数定义添加到类及其在QObject父类中的实现,它提供了添加的C ++特性,如信号/槽,属性, RTTI等。当调用信号和插槽时,内部Qt使用 qt_metacall 功能。对这些here的实现有一个有趣的解释。因此,如果在从QObject派生的类中没有Q_OBJECT宏,则信号和插槽将不起作用。