Qt moc with implementations inside of header files?
Asked Answered
M

4

21

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?

Marlenmarlena answered 8/6, 2010 at 21:57 Comment(1)
Note: The question the user wanted answered was how to use MOC in a unity build (i. e. only one translation unit).Chippewa
M
-3

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

Marlenmarlena answered 11/1, 2011 at 23:18 Comment(18)
This is wrong: it results in multiple compilation of moc_xxxx.cpp and violates the one definition rule. Your code may fail to link, or you may run into other problems. If you insist on manually including moc_xxxx.cpp, you must do it in a single .cpp file only, and never in a header file. cmake/qmake will automatically generate rules to separately compile moc_xxxx.cpp. This applies to qt3, 4 and 5.Papa
No it's not. Looking at my compile output, there is only 1 of each moc_*.cpp file generated. It's been working flawlessly for years AND makes development a whole lot easier.Marlenmarlena
Sure there's only one moc_*.cpp file generated, but you're compiling its contents multiple times, unless you have // myobject.cpp missing in your code snippet. So far it appears as if you include it in the header, and that's wrong, since the header will be, presumably, included in multiple *.cpp files and will get compiled multiple times. This probably won't even link.Papa
qmake and cmake will generate rules to separately compile moc_*.cpp anyway, so what you're doing is redundant. Your code will work just fine without that line present. There are very few circumstances where including moc_*.cpp is necessary - I can't think why would you ever want it without including *.moc first, so that's a special circumstance I have found in one file in my projects. It's a different story with including *.moc, of course.Papa
You have no idea what you're talking about. I'll bet money you haven't even tried to compile my code.Marlenmarlena
I did, though I didn't have to, and it doesn't build, and I stand by my words, and I urge you to understand what I mean. If something I said makes no sense to you, please ask for clarification, I will do my best. Yes, the code, as you have shown does not build if you include "myobject.h" in more than one .cpp file. It can't. The linker will complain about duplicate symbols. Again, I assume that the entire code snippet of yours shows one file: myobject.h, and no other file. If you then proceed to include myobject.h in two or more .cpp files, it won't link anymore.Papa
Please recall that .h files are meant to be included in possibly very many source files, whose results of compilation are then linked together into one executable or library. If your project(s) where you use this misguided approach happen to include header files in only one source file, and no others, then yes, your project will build. It will still build if you remove #include "moc_xxxx.cpp", of course, so what's the point?Papa
So, I have downvoted the answer because it advises bad practice for absolutely no reasons given. In my projects, I have one .cpp file that includes a moc_xxx.cpp, but again: that's a .cpp file that does the including, and not an .h file as you show, and there is a rather obscure and likely uninteresting reason for it to be so - thus I won't even elaborate on that.Papa
If you can't compile that code, you're not a very good developer and I question your reputation score.Marlenmarlena
I don't use CPP files in my projects. I declare and implement ALL methods in the header file and include moc_.cpp at the end. You should know that the moc_.cpp files are not written by me (if you knew anything). They are generated by MOC. Are you daft or something?Marlenmarlena
You obviously have no clue how Qt works so why not take the time to learn? That way you don't bother other people with your jibber jabber and actually learn something new so you can KNOW what you're talking about.Marlenmarlena
"I don't use CPP files in my projects." First of all, you never said it before, and I didn't assume so because it's not possible to do for "HUGE" projects as you claim. Not without limiting yourself to a subset of C++. If you have static class members or global variables defined in a header, as soon as you include such a header into another header, you have multiple definitions. Same goes for moc output. The subset of C++ that you limit yourself to excludes global variables, static class members, and out-of-class member definitions. Moc output simply won't work here, not the way you use it.Papa
I really can't see how you can have any project that does anything useful that doesn't include at least one header (with included moc output) in multiple translation units, unless you concatenate all your headers into one translation unit. If you do so, without mentioning it, then I rest my case. It's kind of an important detail not to be mentioned. The project you show here does that: it concatenates all headers into main.cpp, and only compiles main.cpp. Technically it's an OK thing to do. Practically, you're paying huge compile time penalties for doing it, with no other benefits in LTCG era.Papa
The project in this answer will fail to build as soon as you include either header file in another .cpp file. So, advocating it as some general strategy is IMHO misguided.Papa
At the very least, the question and the answer are purposefully obfuscating what you're trying to do, and giving no reasons for doing so. In C/C++, the .h extension is an idiom that doesn't mean "I'm included somewhere else". The semantics are strict: .h's inclusion in multiple translation units will not violate the one definition rule. That's why moc's output has the .cpp extension, not .h extension. Your "headers", at the very least, aren't - they are sources that you proceed to concatenate into main.cpp. They should have .cpp extensions.Papa
Everyone else expects that .h can be included in multiple translation units, and whoever would take over your projects will be highly confused by this not being the case. The moc output that the build system would separately compile for you, can't be handled so, since the non-headers are included in moc output, and would appear in multiple translation units. That's why you need to include moc output explicitly. What you're doing is manually concatenating everything into one source file - with all the extra busywork it entails. It made sense in the days of KDE3/4. Maybe.Papa
Putting function definitions in the header without inlining them is definitely not the "best way".Chippewa
In this kind of unity build, the class at the bottom of the include chain will not be able to reference anything above it. In the example above, MyWidget will not be able to call Window's public methods. Instead, it is the upper class's job to tell the lower class what to do, and give what it needs.Mediatize
A
22

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.

Abigailabigale answered 9/6, 2010 at 11:36 Comment(6)
I think you mean qmake make rather than the other way around? :)Discerning
No I don't. You only have to run qmake once to create you Makefile s. If you want to rerun moc afterwards, just run make qmake.Abigailabigale
Couldn't get it to work.. Seems like I'm out of luck. Thanks anyways.Marlenmarlena
Sorry, I didn't realise you meant one command i.e. qmake was a make target. I didn't know that target even existed! On my system it looks as if all that target does is to run qmake so I guess it's identical to run qmake followed by make. That's certainly the way I've always done it.Discerning
@Job Can you elaborate the reason for that? I understood it as by default compiler create .moc files for all header files which contain Q_OBJECT. When user has Q_OBJECT in .cpp file he has to manually include relevant .moc file to create a single translation unit. Is it correct?Kenway
thanks ! Qt does have its mysteries !Monroe
H
16

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:

  1. MyObject.moc must be included at the end of MyObject.cpp iff you declare any Q_OBJECT classes within MyObject.cpp.

  2. moc_MyObject.cpp can be included anywhere in MyObject.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:

  1. moc_foo.cpp from foo.h, iff foo.h contains Q_OBJECT macro.

  2. foo.moc from foo.cpp, iff foo.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 and MyObject.cpp are the files you write.
  • MyObject.cpp and moc_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"
...
Heintz answered 26/3, 2015 at 20:1 Comment(2)
The book you just wrote proves nothing. The fact still remains that my code compiles and you've not provided proof that any part of my code is compiled twice or that my method of development is "wrong" in any way.Marlenmarlena
@Sosukodo I've told you already that your code compiles, but doesn't link as soon as you include the header in more than one .cpp file. I hope that's clear. Again, I'm not out to prove anything, I merely describe how things are.Papa
S
4

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.

Selfabuse answered 13/6, 2010 at 9:37 Comment(2)
Thanks! That worked nicely. Just to be clear, I can't do forward declarations this way, right? I tried and got errors :-) I guess you can't have everything!Marlenmarlena
You are welcome! I think it is not possible since you have no cpp file to give the header for the forward declaration.Selfabuse
M
-3

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

Marlenmarlena answered 11/1, 2011 at 23:18 Comment(18)
This is wrong: it results in multiple compilation of moc_xxxx.cpp and violates the one definition rule. Your code may fail to link, or you may run into other problems. If you insist on manually including moc_xxxx.cpp, you must do it in a single .cpp file only, and never in a header file. cmake/qmake will automatically generate rules to separately compile moc_xxxx.cpp. This applies to qt3, 4 and 5.Papa
No it's not. Looking at my compile output, there is only 1 of each moc_*.cpp file generated. It's been working flawlessly for years AND makes development a whole lot easier.Marlenmarlena
Sure there's only one moc_*.cpp file generated, but you're compiling its contents multiple times, unless you have // myobject.cpp missing in your code snippet. So far it appears as if you include it in the header, and that's wrong, since the header will be, presumably, included in multiple *.cpp files and will get compiled multiple times. This probably won't even link.Papa
qmake and cmake will generate rules to separately compile moc_*.cpp anyway, so what you're doing is redundant. Your code will work just fine without that line present. There are very few circumstances where including moc_*.cpp is necessary - I can't think why would you ever want it without including *.moc first, so that's a special circumstance I have found in one file in my projects. It's a different story with including *.moc, of course.Papa
You have no idea what you're talking about. I'll bet money you haven't even tried to compile my code.Marlenmarlena
I did, though I didn't have to, and it doesn't build, and I stand by my words, and I urge you to understand what I mean. If something I said makes no sense to you, please ask for clarification, I will do my best. Yes, the code, as you have shown does not build if you include "myobject.h" in more than one .cpp file. It can't. The linker will complain about duplicate symbols. Again, I assume that the entire code snippet of yours shows one file: myobject.h, and no other file. If you then proceed to include myobject.h in two or more .cpp files, it won't link anymore.Papa
Please recall that .h files are meant to be included in possibly very many source files, whose results of compilation are then linked together into one executable or library. If your project(s) where you use this misguided approach happen to include header files in only one source file, and no others, then yes, your project will build. It will still build if you remove #include "moc_xxxx.cpp", of course, so what's the point?Papa
So, I have downvoted the answer because it advises bad practice for absolutely no reasons given. In my projects, I have one .cpp file that includes a moc_xxx.cpp, but again: that's a .cpp file that does the including, and not an .h file as you show, and there is a rather obscure and likely uninteresting reason for it to be so - thus I won't even elaborate on that.Papa
If you can't compile that code, you're not a very good developer and I question your reputation score.Marlenmarlena
I don't use CPP files in my projects. I declare and implement ALL methods in the header file and include moc_.cpp at the end. You should know that the moc_.cpp files are not written by me (if you knew anything). They are generated by MOC. Are you daft or something?Marlenmarlena
You obviously have no clue how Qt works so why not take the time to learn? That way you don't bother other people with your jibber jabber and actually learn something new so you can KNOW what you're talking about.Marlenmarlena
"I don't use CPP files in my projects." First of all, you never said it before, and I didn't assume so because it's not possible to do for "HUGE" projects as you claim. Not without limiting yourself to a subset of C++. If you have static class members or global variables defined in a header, as soon as you include such a header into another header, you have multiple definitions. Same goes for moc output. The subset of C++ that you limit yourself to excludes global variables, static class members, and out-of-class member definitions. Moc output simply won't work here, not the way you use it.Papa
I really can't see how you can have any project that does anything useful that doesn't include at least one header (with included moc output) in multiple translation units, unless you concatenate all your headers into one translation unit. If you do so, without mentioning it, then I rest my case. It's kind of an important detail not to be mentioned. The project you show here does that: it concatenates all headers into main.cpp, and only compiles main.cpp. Technically it's an OK thing to do. Practically, you're paying huge compile time penalties for doing it, with no other benefits in LTCG era.Papa
The project in this answer will fail to build as soon as you include either header file in another .cpp file. So, advocating it as some general strategy is IMHO misguided.Papa
At the very least, the question and the answer are purposefully obfuscating what you're trying to do, and giving no reasons for doing so. In C/C++, the .h extension is an idiom that doesn't mean "I'm included somewhere else". The semantics are strict: .h's inclusion in multiple translation units will not violate the one definition rule. That's why moc's output has the .cpp extension, not .h extension. Your "headers", at the very least, aren't - they are sources that you proceed to concatenate into main.cpp. They should have .cpp extensions.Papa
Everyone else expects that .h can be included in multiple translation units, and whoever would take over your projects will be highly confused by this not being the case. The moc output that the build system would separately compile for you, can't be handled so, since the non-headers are included in moc output, and would appear in multiple translation units. That's why you need to include moc output explicitly. What you're doing is manually concatenating everything into one source file - with all the extra busywork it entails. It made sense in the days of KDE3/4. Maybe.Papa
Putting function definitions in the header without inlining them is definitely not the "best way".Chippewa
In this kind of unity build, the class at the bottom of the include chain will not be able to reference anything above it. In the example above, MyWidget will not be able to call Window's public methods. Instead, it is the upper class's job to tell the lower class what to do, and give what it needs.Mediatize

© 2022 - 2024 — McMap. All rights reserved.