0

当有信息消息或发生错误时,我有一个应该发出信号的类applicationManager,而我想通过 QXmppLogger 类对象记录使用它的消息。有一个 QXmppLoggable 类,它具有类似的方法info()warning()发出logmessage()内部 QXmppLogger 的信号。因此,为了发出信号,我继承了 QXmppLogable 类,该类继承了 QObject 本身,因此能够使用info()并通过 info() 和 warning() 方法warning()将发出的 SIGNAL( ) 连接到QXmppLogger 对象的 SLOT()。这是代码片段:logmessage()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();
}

编译通知没有错误,但是当启动时有一个 Sigmentation 错误。我该如何解决?

4

3 回答 3

3

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

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

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

    1. 将指针传递给 的构造函数中的记录器applicationManagement,这样您就可以在构造函数中连接一些东西。这样你就不能applicationManagement在记录器之前实例化一个,除非你logger(new QXmppLogger)在构造函数初始化列表中使用。

    2. 将连接从applicationManagement构造函数移至setLogger()方法。不要忘记断开以前的连接(如果有)。

于 2013-08-20T09:34:19.670 回答
2

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

Qt 为 C++ 添加了信号和插槽的功能以及其他功能,这是通过 Meta-Object Compiler(或简称为 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函数。这里有一个关于这些实现的有趣解释。因此,如果没有从 QObject 派生的类中的 Q_OBJECT 宏,信号和插槽将无法工作。

于 2013-08-20T10:39:32.840 回答
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)));
}

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

于 2013-08-20T09:20:07.133 回答