Question

Est-il possible de dire Qt MOC que je voudrais déclarer la classe et la mettre en œuvre dans un seul fichier plutôt que les diviser dans un fichier .h et .cpp?

Était-ce utile?

La solution 4

Je crois que ce soit la meilleure façon. Il est en fait la façon dont je construis tous mes objets maintenant.

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

Construire ... qmake Works.pro

make

Autres conseils

Si vous voulez déclarer et mettre en œuvre une sous-classe de QObject dans votre fichier cpp, vous devez inclure manuellement le fichier moc.

Par exemple: (fichier main.cpp)

struct SubObject : QObject
{
    Q_OBJECT
};

//...

#include "main.moc"

Vous devez exécuter à nouveau moc (make qmake) après avoir ajouté l'instruction #include.

TL; DR

Oui, si vous parlez seulement les fichiers que vous écrivez vous-même (par opposition que ceux générés par moc). Vous n'avez pas besoin de faire quoi que ce soit spécial.

Si vous souhaitez toujours inclure la sortie moc explicitement dans les fichiers que vous écrivez, il y a un cas où vous devez le faire, et un cas où vous peut souhait pour le faire. Supposons que la classe MyObject est déclarée dans MyObject.h et votre définition de celui-ci est donnée dans MyObject.cpp:

  1. MyObject.moc doit être inclus à la fin de MyObject.cpp ssi vous déclarez toutes les classes de Q_OBJECT dans MyObject.cpp.

  2. moc_MyObject.cpp peut être inclus partout MyObject.cpp à réduire de moitié le nombre d'unités de traduction dans votre projet. Il est une optimisation accumulation de temps seulement. Si vous ne le faites pas, moc_MyObject.cpp sera compilé séparément.

Chaque fois que vous ajoutez ou supprimez macro Q_OBJECT de tout fichier source ou en-tête, ou vous ajoutez ou supprimez des inclusions explicites de sortie moc dans ces fichiers, vous devez exécuter qmake / CMake.

Pour Réexécutez qmake / CMake dans Qt Creator, simplement un clic droit sur le projet de premier niveau, et sélectionnez Exécuter qmake ou Exécuter CMake dans le menu contextuel.

La réponse

Un exemple de projet Qt base qmake peut consister en trois fichiers, comme suit:

# 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

Il ne fait pas beaucoup, mais il est certainement valable. Mis à part les différentes bibliothèques qui relie le système de construction de notre projet, il y a deux projets spécifiques une règle définition , pour être exact, et donne ainsi un invalide C ++ programme.

Maintenant, vous pourriez penser à obtenir « intelligent » et inclure de force la sortie moc dans le fichier d'en-tête. Les qmake / cmake / QBS seront de logement, et le détectera et ne seront pas traiter séparément sortie moc par le compilateur touteplus, comme vous l'avez déjà fait.

Alors, supposons que, dans le projet ci-dessus, vous avez changé myobject.h comme suit:

// 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

En l'état actuel, le projet sera toujours compiler, apparemment remplir votre objectif d'avoir un seul fichier qui définit l'ensemble des MyObject - les bits que vous avez écrit, et les bits qui Moc générés, les deux. Mais il est seulement en raison d'une heureuse circonstance improbable: le contenu de moc_*.cpp sont toujours en une seule unité de traduction -

Supposons maintenant que l'on ajoute un second fichier source à notre projet:

# test.pro
QT       += core
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h

// test.cpp
#include "myobject.h"

Pas grand-chose à elle. Il devrait fonctionner, même si elle ne fait pas grand-chose, non?

Hélas, il ne sera pas un lien. Maintenant, le contenu de moc_myobject.cpp font partie de deux unités de traduction. Étant donné que les faces intérieures de moc_myobject.cpp sont pleins de membres de classe autonomes définitions, cela porte atteinte à la une règle définition . une unité de traduction Les mandats des règles que les définitions autonomes uniquement peuvent apparaître dans une cible. L'éditeur de liens, être le gardien de cette règle, se plaint à juste titre.

Le Y compris sortie moc dans le fichier .cpp

Comme mentionné dans le TL; DR., Aucun des ci-dessus exclut l'inclusion explicite de la production moc dans les fichiers source (Cpp), dans des circonstances particulières

Etant donné « foo.h » et « foo.cpp », et un projet géré par qmake ou CMake, le système de construction dirigera moc générer jusqu'à deux sorties:

  1. moc_foo.cpp de foo.h, ssi foo.h contient macro Q_OBJECT.

  2. foo.moc de foo.cpp, iff foo.cpp contient #include "foo.moc".

Examinons en détail pourquoi voudriez-vous d'inclure un ou l'autre dans un fichier .cpp.

Y compris xxx.moc

Parfois, en particulier dans les jours avant 11 C ++ et Qt 5, il est très utile de déclarer les petites classes de QObject d'aide pour l'utilisation locale dans une unité de traduction (fichier source) uniquement.

est également à portée de main lors de l'écriture unique fichier, cas de test autonomes et des exemples pour stackoverflow.

Supposons que vous vouliez quelqu'un de démontrer, dans un fichier, comment appeler une fente de la boucle d'événement:

// 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"

Depuis MyObject est une petite classe qui est utilisé localement dans main.moc, il ne serait pas beaucoup de sens de mettre sa définition dans un fichier d'en-tête séparé. La ligne de #include "main.moc" sera remarqué par qmake / CMake et main.cpp sera alimenté par moc, ce qui main.moc. Depuis main.moc définit les membres de MyObject, il doit être inclus quelque part où MyObject est déclarée. Comme la déclaration est dans main.cpp, vous ne pouvez pas avoir main.moc une unité de traduction séparée: il ne compilera pas en raison de MyObject étant non déclarée. Le seul endroit où elle est déclarée est dans main.cpp, quelque part vers la fin. Voilà pourquoi il est un pari sûr de toujours inclure foo.moc à la fin de foo.cpp.

Un lecteur astucieux demande maintenant: comment se moc_foo.cpp obtient les déclarations des classes dont les membres définit? Tout simplement: il inclut explicitement le fichier d'en-tête, il est généré à partir (ici: foo.h). Bien sûr foo.moc ne peut pas le faire, car il brisaient la règle de définition unique en définissant multiplier tout foo.cpp.

Y compris moc_xxx.cpp

En particulier les grands projets Qt, vous pourriez avoir - en moyenne - deux fichiers et deux unités de traduction par chaque classe:

  • MyObject.h et MyObject.cpp sont les fichiers que vous écrivez.
  • MyObject.cpp et moc_MyObject.cpp sont les unités de traduction.

Il est possible de réduire de moitié le nombre d'unités de traduction en incluant explicitement moc_MyObject.cpp quelque part dans MyObject.cpp:

// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...

Je pense que vous pouvez normalement déclarer et mettre en œuvre la classe dans le fichier d'en-tête sans utiliser quelque chose de spécial, par exemple:

#include <QObject>

class MyClass : public QObject
{
  Q_OBJECT

  public:
     MyClass(QObject * parent)
     {
        // Constructor Content
     }

     methodExample()
     {
          // Method content
     }
};

Après cela, vous ajoutez le fichier d'en-tête du fichier pri et d'exécuter qmake à nouveau et c'est tout. Vous avez une classe qui hérite de QObject et est mis en œuvre et a déclaré int il .h.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top