是否可以告诉Qt的MOC,我想申报类,并在一个单独的文件执行它,而不是分裂的上了h和.cpp文件?
Answer 1:
如果你想声明,并在您实现一个QObject子类的cpp文件,你必须手动包括商务部的文件。
例如:(文件main.cpp中)
struct SubObject : QObject
{
Q_OBJECT
};
//...
#include "main.moc"
你必须重新运行MOC( make qmake
加入后) #include
声明。
Answer 2:
TL; DR
是的,如果你只是在谈论你自己写的(而不是那些由商务部生成)的文件。 你不需要做什么特别的。
如果你希望明确包括在你写的文件的moc输出,还有一个情况下,你必须做,一个情况下,你可能希望这样做。 让我们假设MyObject
类中声明MyObject.h
和你对它的定义中给出MyObject.cpp
:
MyObject.moc
必须包括在年底MyObject.cpp
当且仅当你声明任何Q_OBJECT
中的类MyObject.cpp
。moc_MyObject.cpp
可以 随时随地中包含MyObject.cpp
减半在项目的翻译单元数量。 这只是一个构建时的优化。 如果你不这样做,moc_MyObject.cpp
将另行编制。
每次添加或删除Q_OBJECT
从任何来源或头文件中的宏,或者您添加或删除的moc输出的明确夹杂在这些文件中,则必须重新运行QMAKE / cmake的。
重新运行QMAKE / cmake的Qt Creator中,只需在顶级项目上单击右键,然后从上下文菜单中运行的qmake或运行cmake。
简单的答案
一个例子基于QMAKE,Qt的项目可能包括三个文件,如下所示:
# test.pro
QT += core
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += myobject.h
// main.cpp
#include "myobject.h"
int main() {
MyObject obj;
obj.staticMetaObject; // refer to a value defined in moc output
return 0;
}
// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject {
Q_OBJECT
public:
MyObject() {}
Q_SLOT void aSlot() {}
};
#endif // MYOBJECT_H
它没有做太多,但它肯定是有效的。 除此之外,构建系统联系我们的项目有不同的库,有两个具体项目的翻译单位 : main.cpp
和moc_myobject.cpp
。
即使它看起来的整个实施MyObject
是在头文件,它真的不是。 该Q_OBJECT
宏声明的实施的某些位将是不确定的,如果不是对MOC-产生的定义。
如何MOC进入了吗? 当项目初建时,元软件包工具-无论是QMAKE或CMake的-扫描存在的所有C ++输入文件Q_OBJECT
宏。 那些含有它,给予特殊待遇。 在这个例子中的项目, myobject.h
包含Q_OBJECT
并通过MOC加工成moc_myobject.cpp
。 后者被添加到由C ++编译器编译的源的列表。 它,只是概念上的,因为如果你有SOURCES += moc_myobject.cpp
中.pro
文件。 当然,你应该这样一行从未添加到.pro文件。
现在可以看到的整个实施MyObject
掌握在两个文件: myobject.h
和moc_myobject.cpp
。 myobject.h
可以包含在许多翻译单元,你的愿望-因为有这将违反一个定义规则没有超出级(独立)的定义。 构建体系将moc_myobject.cpp
作为一个单一的,独立的翻译单位-这是所有采取的为你服务。
因此,你的目标是达到了,没有力气都:你有什么特别要做把整个实施MyObject
-保存,交通部产生位-为头文件。 它可能会延长编译时间,但在其他无害的。
一个规则,违反法
它违反了一个定义规则 ,准确的,因而产生一个无效的C ++程序。
现在,你可能会认为得到“聪明”,强行包括商务部输出到头文件。 该QMAKE / cmake的/ QBS将被容纳,并且将检测到这一点,并不会单独再处理编译通过MOC输出,你已经做到了。
因此,假设是,在上述项目中,你改变了myobject.h
内容如下:
// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
class MyObject : public QObject {
Q_OBJECT
public:
MyObject() {}
Q_SLOT void aSlot() {}
};
#include "moc_myobject.cpp"
#endif // MYOBJECT_H
既然这样,该项目将仍然编译,看似履行其只是一个文件,它定义的全部的你的目标MyObject
-你写的位,并且MOC产生的位,两者。 但是,这只是一个不太愉快的情况原因:内容moc_*.cpp
仍然只在一个翻译单元-
假设,现在我们第二个源文件添加到我们的项目:
# test.pro
QT += core
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h
// test.cpp
#include "myobject.h"
不多了。 它应该工作,即使它没有做太多,对不对?
可惜的是,它不会链接。 现在的内容moc_myobject.cpp
是两个翻译单元的一部分。 由于moc_myobject.cpp
的内心都充满了单机类成员的定义,这违反了一个定义规则 。 该规则授权独立定义可能只有一个目标之内出现在一个翻译单元 。 链接器,是这个规则的守护者,理所当然地抱怨。
在包括在.cpp文件MOC输出
正如在TL提到; DR,没有上述排除了源(的.cpp)文件的moc输出的显式包含,在特定情况下。
鉴于“了foo.h”和“Foo.cpp中”,并通过QMAKE或CMake的管理项目,构建系统会直接moc
产生高达两个输出:
moc_foo.cpp
从foo.h
, 当且仅当foo.h
含有Q_OBJECT
宏。foo.moc
从foo.cpp
, 当且仅当foo.cpp
包含#include "foo.moc"
让我们来详细探讨为什么你想为包括一个在.cpp文件。
包括xxx.moc
有时,特别是在之前的C ++ 11和Qt 5天,说到方便的只有一个翻译单元(源文件)内本地使用申报小帮手的QObject类。
写单文件,自包含的测试案例和示例计算器使用时,这也来得心应手。
假设你希望有人证明,在一个文件中,如何调用从事件循环槽:
// main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <cstdio>
QTextStream out(stdout);
class MyObject : public QObject {
Q_OBJECT
public:
MyObject() {}
Q_SLOT void mySlot() { out << "Hello from " << __FUNCTION__ << endl; }
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
MyObject obj;
QMetaObject::invokeMethod(&obj, Qt::QueuedConnection, "mySlot");
QMetaObject::invokeMethod(&app, Qt::QueuedConnection, "quit");
return app.exec();
}
#include "main.moc"
由于MyObject
是,只有在本地使用一个小班main.moc
,那就没有多大意义,把它定义成一个单独的头文件。 所述#include "main.moc"
线将通过的qmake / cmake的被注意到,并且main.cpp
将通过MOC供给,导致main.moc
。 由于main.moc
定义的成员MyObject
,它必须被包括其中某个地方MyObject
被声明。 由于声明中main.cpp
,你不能有main.moc
是一个单独的翻译单元:它不会因编译到MyObject
被未声明。 在声明的地方是内main.cpp
,接近尾声的地方。 这就是为什么它是一个安全的赌注,始终包括foo.moc
在结束foo.cpp
。
聪明的读者现在问:怎么来moc_foo.cpp
得到其成员,它定义的类的声明? 很简单:它明确包含它是从(这里:所产生的头文件foo.h
)。 当然foo.moc
不能这样做,因为它会通过乘法定义的一切打破单一定义规则foo.cpp
。
包括moc_xxx.cpp
在特别大的Qt项目,你可能有-平均-两个文件以及每个班两个平移单位:
-
MyObject.h
和MyObject.cpp
是你写的文件。 -
MyObject.cpp
和moc_MyObject.cpp
是翻译单元。
有可能通过明确包括减半的翻译单元数量moc_MyObject.cpp
在某处MyObject.cpp
:
// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...
Answer 3:
我认为你能正常声明和实现在头文件中的类,而无需使用任何特殊,例如:
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject * parent)
{
// Constructor Content
}
methodExample()
{
// Method content
}
};
在这之后,你的头文件添加到PRI文件,然后再执行qmake的,就是这样。 你必须从Qobject继承和实现,并宣布诠释他的.h文件中的类。
Answer 4:
我相信这是最好的方式。 它实际上是我现在该怎么构建我的所有对象。
Qt的4.8.7
Works.pro:
SOURCES += \
main.cpp
HEADERS += \
Window.h \
MyWidget.h
main.cpp中
#include <QtGui>
#include "Window.h"
int main(int argc, char *argv[])
{
QApplication app(argc,argv);
Window window;
window.show();
return app.exec();
}
在window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QtGui>
#include "MyWidget.h"
class Window : public QWidget
{
Q_OBJECT
private:
MyWidget *whatever;
public:
Window()
{
QHBoxLayout *layout = new QHBoxLayout;
setLayout(layout);
whatever = new MyWidget("Screw You");
layout->addWidget(whatever);
}
};
#include "moc_Window.cpp"
#endif // WINDOW_H
MyWidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QtGui>
class MyWidget : public QLabel
{
Q_OBJECT
public:
MyWidget(QString text) : QLabel(text)
{
// Whatever
}
};
#include "moc_MyWidget.cpp"
#endif // MYWIDGET_H
建立... QMAKE Works.pro
使