Is it possible to tell the Qt MOC that I would like to declare the class and implement it in a single file rather than splitting them up into an .h and .cpp file?
If you want to declare and implement a QObject subclass in you cpp file, you have to manually include the moc file.
For example: (file main.cpp)
struct SubObject : QObject
{
Q_OBJECT
};
//...
#include "main.moc"
You have to rerun moc (make qmake
) after adding the #include
statement.
TL;DR
Yes, if you're talking only about the files that you write yourself (as opposed as those generated by moc). You don't need to do anything special at all.
If you ever wish to include moc output explicitly in the files you write, there is one case in which you must do it, and one case where you might wish to do it. Let's assume that MyObject
class is declared in MyObject.h
and your definition of it is given in MyObject.cpp
:
MyObject.moc
must be included at the end ofMyObject.cpp
iff you declare anyQ_OBJECT
classes withinMyObject.cpp
.moc_MyObject.cpp
can be included anywhere inMyObject.cpp
to halve the number of translation units in your project. It's a build-time optimization only. If you don't do it,moc_MyObject.cpp
will be separately compiled.
Every time you add or remove Q_OBJECT
macro from any source or header file, or you add or remove explicit inclusions of moc output in such files, you must re-run qmake/cmake.
To re-run qmake/cmake in Qt Creator, simply right-click on the toplevel project, and select Run qmake or Run cmake from the context menu.
The Simple Answer
An example qmake-based Qt project might consist of three files, as follows:
# 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
It doesn't do much, but it's certainly valid. Apart from the various libraries that the build system links our project with, there are two project-specific translation units: main.cpp
and moc_myobject.cpp
.
Even though it appears that the entire implementation of MyObject
is in the header file, it really isn't. The Q_OBJECT
macro declares some bits of implementation that would be undefined, if it weren't for the moc-generated definitions.
How does moc enter into the picture? When the project is first built, the metabuild tool - either qmake or cmake - scans all the C++ input files for the presence of Q_OBJECT
macro. Those that contain it, are given special treatment. In this example project, myobject.h
contains Q_OBJECT
and is processed through moc into moc_myobject.cpp
. The latter is added to the list of sources that are compiled by the C++ compiler. It is, only conceptually, as if you had SOURCES += moc_myobject.cpp
in the .pro
file. Of course you should never add such a line to the .pro file.
Now notice that the entire implementation of MyObject
rests in two files: myobject.h
and moc_myobject.cpp
. myobject.h
can be included in as many translation units as you desire - because there are no out-of-class (standalone) definitions that would violate the one definition rule. The build system treats moc_myobject.cpp
as a single, separate translation unit - this is all taken care of for you.
Thus your goal is reached with no effort at all: You have nothing special to do to put the entire implementation of MyObject
- save for the bits that moc produces - into the header file. It may prolong the compilation times, but is otherwise innocuous.
A Rule-Violating Approach
It violates the one definition rule, to be exact, and thus yields an invalid C++ program.
Now you might think to get "clever" and forcibly include the moc output into the header file. The qmake/cmake/qbs will be accommodating, and will detect this and won't separately process moc output through the compiler anymore, as you've already done it.
So, suppose that, in the project above, you changed myobject.h
to read as follows:
// 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
As it stands, the project will still compile, seemingly fulfilling your goal of having just one file that defines the entirety of MyObject
- the bits that you wrote, and the bits that moc generated, both. But it's only due to an unlikely happy circumstance: the contents of moc_*.cpp
are still in only one translation unit -
Suppose, now that we add a second source file to our project:
# test.pro
QT += core
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h
// test.cpp
#include "myobject.h"
Not much to it. It should work, even if it doesn't do much, right?
Alas, it won't link. Now the contents of moc_myobject.cpp
are a part of two translation units. Since moc_myobject.cpp
's insides are full of stand-alone class member definitions, this violates the one definition rule. The rule mandates that stand-alone definitions may only appear in one translation unit within a target. The linker, being the guardian of this rule, rightly complains.
On Including moc Output in the .cpp File
As alluded to in the TL;DR, none of the above precludes explicit inclusion of moc output in source (.cpp) files, in specific circumstances.
Given "foo.h" and "foo.cpp", and a project managed by qmake or cmake, the build system will direct moc
to generate up to two outputs:
moc_foo.cpp
fromfoo.h
, ifffoo.h
containsQ_OBJECT
macro.foo.moc
fromfoo.cpp
, ifffoo.cpp
contains#include "foo.moc"
.
Let's examine in detail why would you want to include either one in a .cpp file.
Including xxx.moc
Sometimes, especially in the days prior to C++11 and Qt 5, it comes handy to declare small helper QObject classes for local use within one translation unit (source file) only.
This also comes handy when writing single-file, self-contained test cases and examples for stackoverflow use.
Suppose you wished someone to demonstrate, in one file, how to invoke a slot from the event loop:
// 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"
Since MyObject
is a small class that's only used locally in main.moc
, it wouldn't make much sense to put its definition into a separate header file. The #include "main.moc"
line will be noticed by qmake/cmake, and main.cpp
will be fed through moc, resulting in main.moc
. Since main.moc
defines members of MyObject
, it must be included someplace where MyObject
is declared. As the declaration is within main.cpp
, you can't have main.moc
be a separate translation unit: it won't compile due to MyObject
being not declared. The only place where it is declared is within main.cpp
, somewhere towards the end. That's why it's a safe bet to always include foo.moc
at the end of foo.cpp
.
An astute reader now asks: how come moc_foo.cpp
gets the declarations of the classes whose members it defines? Quite simply: it explicitly includes the header file it is generated from (here: foo.h
). Of course foo.moc
can't do that, since it'd break the single definition rule by multiply defining everything in foo.cpp
.
Including moc_xxx.cpp
In particularly large Qt projects, you might have - on average - two files and two translation units per each class:
MyObject.h
andMyObject.cpp
are the files you write.MyObject.cpp
andmoc_MyObject.cpp
are the translation units.
It is possible to halve the number of translation units by explicitly including moc_MyObject.cpp
somewhere in MyObject.cpp
:
// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...
I think you can normally declare and implement the class in the header file without using anything special, eg:
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject * parent)
{
// Constructor Content
}
methodExample()
{
// Method content
}
};
After this you add the header file to the pri file and execute qmake again and that's it. You have a class that inherits from qobject and is implemented and declared int he .h file.
I believe this to be the best way. It's actually how I construct all of my objects now.
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
Build... qmake Works.pro
make
来源:https://stackoverflow.com/questions/3001615/qt-moc-with-implementations-inside-of-header-files