我有一个类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错误。 我该如何解决这个问题?
答案 0 :(得分:3)
好的,决定发表一个完整的答案:
首先,您需要Q_OBJECT
宏。当您从QtCreator的Clean All
菜单中Run qmake
,Rebuild All
和Build
时,您从中获得的错误可能会消失。 Qt依赖于您不必键入的大量生成的样板代码,并且没有Q_OBJECT
代码将不会生成。这就是您在进行更改后有时需要清理的原因,运行qmake(生成代码)并使用现在最新生成的代码重建。
第二 - 在applicationManagement
的构造函数中,您连接到未初始化的指针记录器。这可能是您获得分段错误的原因。您可以使用两种方法来解决这个问题:
将指针传递给applicationManagement
构造函数中的记录器,这样就可以在构造函数中连接到某些内容。这样,除非在构造函数初始化列表中使用applicationManagement
,否则无法在记录器之前实例化logger(new QXmppLogger)
。
将连接从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宏,则信号和插槽将不起作用。