Domanda

E 'possibile dire al Qt MOC che vorrei dichiarare la classe e la sua attuazione in un unico file, piuttosto che dividere in su in un file .he cpp?

È stato utile?

Soluzione 4

Credo che questo sia il modo migliore. E 'in realtà come costruisco tutti i miei oggetti ora.

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

Crea ... qmake Works.pro

make

Altri suggerimenti

Se si vuole dichiarare e implementare una sottoclasse QObject in voi il file cpp, è necessario includere manualmente il file moc.

Ad esempio: (file main.cpp)

struct SubObject : QObject
{
    Q_OBJECT
};

//...

#include "main.moc"

È necessario eseguire nuovamente moc (make qmake) dopo aver aggiunto la dichiarazione #include.

TL; DR

Sì, se si parla solo dei file che si scrivono da soli (in contrapposizione, come quelli generati da moc). Non è necessario fare nulla di speciale a tutti.

Se mai desidera includere uscita moc esplicitamente nei file che scrivi, non v'è un caso in cui si deve farlo, e un caso in cui si potrebbe desiderio per farlo. Supponiamo che la classe MyObject viene dichiarata in MyObject.h e la tua definizione di esso è dato in MyObject.cpp:

  1. MyObject.moc deve essere incluso alla fine di MyObject.cpp se e solo se si dichiara tutte le classi Q_OBJECT all'interno MyObject.cpp.

  2. moc_MyObject.cpp può essere incluso ovunque in MyObject.cpp di dimezzare il numero di unità di traduzione nel progetto. Si tratta di un'ottimizzazione accumulo di tempo solo. Se non lo fai, moc_MyObject.cpp sarà compilato separatamente.

Ogni volta che si aggiunge o macro rimuovere Q_OBJECT da qualsiasi file di origine o intestazione, oppure aggiungere o rimuovere inclusioni esplicite di uscita moc in tali file, è necessario ri-run qmake / CMake.

Per re-run qmake / cmake in Qt Creator, è sufficiente fare clic destro sul progetto toplevel, e selezionare Esegui qmake o Esegui cmake dal menu contestuale.

La risposta è semplice

Un progetto Qt qmake a base di esempio potrebbe essere costituito da tre file, come segue:

# 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

Non fa molto, ma è certamente valida. A parte le varie librerie che il sistema di costruire legami con il nostro progetto, ci sono due progetti specifici unità di traduzione : main.cpp e moc_myobject.cpp

.

Anche se sembra che l'intera implementazione di MyObject è nel file di intestazione, in realtà non è. La macro Q_OBJECT dichiara alcuni pezzi di implementazione che sarebbero indefinito, se non fosse per le definizioni MOC-generated.

Come fa moc entrare in scena? Quando il progetto è costruito, lo strumento metapacchetto - sia qmake o CMake - esegue la scansione di tutti i file di input il C ++ per la presenza di macro Q_OBJECT. Quelli che lo contengono, sono dati un trattamento speciale. In questo esempio di progetto, myobject.h contiene Q_OBJECT e viene elaborata attraverso moc in moc_myobject.cpp. Quest'ultimo viene aggiunto all'elenco delle fonti che sono compilati dal compilatore C ++. E ', solo concettualmente, come se si fosse SOURCES += moc_myobject.cpp nel file .pro. Naturalmente si dovrebbe mai aggiungere una riga al file .pro.

Notate ora che il intero realizzazione di resti MyObject in due file: myobject.h e moc_myobject.cpp. myobject.h può essere incluso in un numero di unità di traduzione come volete - perché non ci sono (standalone) definizioni out-of-class che violerebbero la regola una sola definizione. Il sistema di compilazione tratta moc_myobject.cpp come una singola unità di traduzione, separato -. Questo è tutto curato per voi

In questo modo il vostro obiettivo è raggiunto senza sforzo a tutti: Non hai niente di speciale da fare per mettere l'intera realizzazione di MyObject - tranne che per i bit che produce MOC - nel file di intestazione. Può prolungare i tempi di compilazione, ma è comunque innocuo.

Un approccio Rule-La violazione

una regola definizione , per l'esattezza, e produce quindi un invalido C ++ programma.

Ora si potrebbe pensare di ottenere "intelligente" e la forza includere l'output MOC nel file di intestazione. Il qmake / cmake / QBS sarà accomodante, e rileverà ciò e non separatamente elaborare l'output moc attraverso il compilatore qualsiasidi più, come hai già fatto.

Quindi, supponiamo che, nel progetto di cui sopra, si è modificato myobject.h come segue:

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

Nella sua forma attuale, il progetto sarà ancora la compilazione, apparentemente soddisfare il vostro obiettivo di avere un solo file che definisce l'insieme delle MyObject - i bit che hai scritto, e i bit che moc generato, entrambe le cose. Ma è solo a causa di una circostanza felice improbabile: il contenuto di moc_*.cpp sono ancora in una sola unità di traduzione -

Si supponga, ora che aggiungiamo un secondo file di origine al nostro progetto:

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

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

Non c'è molto da esso. Dovrebbe funzionare, anche se non fa molto, giusto?

Purtroppo, non sarà un collegamento. Ora il contenuto di moc_myobject.cpp sono una parte di due unità di traduzione. Dal interni di moc_myobject.cpp sono pieni di definizioni membro di classe stand-alone, questo viola il regola definizione uno . La regola stabilisce che le definizioni stand-alone possono figurare solo in un'unità di traduzione all'interno di un bersaglio. Il linker, essendo il custode di questa regola, giustamente, si lamenta.

sull'inclusione moc output nel file cpp

Come accennato nel TL,. DR, nessuno dei osta inclusione esplicita di uscita moc nel file di origine (cpp), in circostanze specifiche di cui sopra

Data "foo.h" e "foo.cpp", e un progetto gestito da qmake o CMake, il sistema di generazione dirigerà moc di generare fino a due uscite:

  1. moc_foo.cpp da foo.h, se e solo se foo.h contiene Q_OBJECT macro.

  2. foo.moc da foo.cpp, se e solo se foo.cpp contiene #include "foo.moc".

Esaminiamo in dettaglio perché si vuole includere uno dei due in un file cpp.

Compresi xxx.moc

A volte, soprattutto nei giorni prima del C ++ 11 e Qt 5, si tratta a portata di mano per dichiarare piccole classi helper QObject per uso locale all'interno di un'unità di traduzione (file di origine) solo.

Questo avviene anche a portata di mano durante la scrittura di file singolo, casi di test indipendenti ed esempi per l'uso StackOverflow.

Si supponga che si voleva qualcuno per dimostrare, in un unico file, come richiamare uno slot dal ciclo di eventi:

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

Dato MyObject è una piccola classe che viene utilizzato solo localmente in main.moc, non avrebbe molto senso per mettere la sua definizione in un file di intestazione separata. La linea #include "main.moc" sarà notato da qmake / CMake, e main.cpp verrà alimentato attraverso moc, con conseguente main.moc. Dal momento che definisce main.moc membri MyObject, esso deve essere incluso in un posto dove è dichiarato MyObject. Poiché la dichiarazione è dentro main.cpp, non si può avere main.moc essere un'unità di traduzione separata: non si compila a causa di MyObject essere non dichiarato. L'unico luogo in cui si è dichiarata rientra main.cpp, da qualche parte verso la fine. Ecco perché si tratta di una scommessa sicura di includere sempre foo.moc alla fine del foo.cpp.

Un lettore più attento ora si chiede: come mai moc_foo.cpp ottiene le dichiarazioni delle classi i cui membri si definisce? Molto semplicemente: include esplicitamente il file di intestazione viene generato da (qui: foo.h). Naturalmente foo.moc non può farlo, dal momento che sarebbe rompere la regola un'unica definizione definendo moltiplicare tutto in foo.cpp.

Compresi moc_xxx.cpp

In particolare i grandi progetti Qt, si potrebbe avere - in media - due file e di due unità di traduzione per ogni classe:

  • MyObject.h e MyObject.cpp sono i file che scrivi.
  • MyObject.cpp e moc_MyObject.cpp sono le unità di traduzione.

E 'possibile dimezzare il numero di unità di traduzione includendo esplicitamente moc_MyObject.cpp da qualche parte nel MyObject.cpp:

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

Credo che normalmente è possibile dichiarare e implementare la classe nel file di intestazione senza utilizzare niente di speciale, ad esempio:

#include <QObject>

class MyClass : public QObject
{
  Q_OBJECT

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

     methodExample()
     {
          // Method content
     }
};

Dopo questo si aggiunge il file di intestazione al file pri ed eseguire qmake di nuovo e il gioco è fatto. Si dispone di una classe che eredita da QObject e viene implementato e dichiarato int egli .h file.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top