Ho appena iniziato a usare Qt e ho notato che tutte le definizioni di classe di esempio hanno la macro Q_OBJECT
come prima riga. Qual è lo scopo di questa macro preprocessore?
Ho appena iniziato a usare Qt e ho notato che tutte le definizioni di classe di esempio hanno la macro Q_OBJECT
come prima riga. Qual è lo scopo di questa macro preprocessore?
Risposte:
Dalla documentazione di Qt :
Il Meta-Object Compiler, moc, è il programma che gestisce le estensioni C ++ di Qt.
Lo strumento moc legge un file di intestazione C ++. Se trova una o più dichiarazioni di classe che contengono la macro Q_OBJECT, produce un file sorgente C ++ contenente il codice meta oggetto per quelle classi. Tra le altre cose, è richiesto il codice meta oggetto per il meccanismo di segnali e slot, le informazioni sul tipo di runtime e il sistema di proprietà dinamico.
Q_OBJECT::connect()
ma piuttosto solo connect()
?
Dice semplicemente al pre-compilatore che questa classe ha elementi gui e deve essere eseguita attraverso il 'moc', devi solo aggiungere questo alle classi che usano il meccanismo segnale / slot.
Ma verrà tranquillamente ignorato in qualsiasi altra classe - si aggiunge solo al tempo di compilazione.
Q_OBJECT
interruzioni qobject_cast
e introspezione. Può portare ad un comportamento sconcertante, quindi è una cattiva idea.
Q_OBJECT
verrà "tranquillamente" ignorato in qualsiasi altra (non QObject
) classe. Secondo lo standard C ++, introduce un comportamento indefinito dichiarando diverse funzioni membro e variabili che non vengono mai definite. Inoltre, inquina lo spazio dei nomi della tua classe con QObject
membri specifici. Ad esempio, un po ' Q_OBJECT
potrebbe rompere una classe non correlata che contiene un metodo chiamato metaObject
.
Q_OBJECT
macro, ha perfettamente senso avere classi non gui con la macro, così come le classi gui senza la macro. La macro è utile, ma non è limitata né richiesta per le classi gui.
Il MOC (compilatore meta oggetto) converte i file di intestazione inclusi macro Q_OBJECT in codice sorgente equivalente C ++. In pratica controlla il meccanismo dello slot del segnale e lo rende comprensibile al compilatore C ++
Q_OBJECT
macro viene espansa dal compilatore, moc non è necessario per quello. Il moc non fa nulla con la macro stessa, ma genera le definizioni delle variabili e dei metodi membri che la Q_OBJECT
macro ha dichiarato .
1 Dalla documentazione Qt di The Meta-Object System
Lo strumento moc legge un file sorgente C ++. Se trova una o più dichiarazioni di classe che contengono la macro Q_OBJECT, produce un altro file sorgente C ++ che contiene il codice meta oggetto per ciascuna di quelle classi. Questo file sorgente generato può essere # incluso nel file sorgente della classe o, più comunemente, compilato e collegato con l'implementazione della classe.
2 Dalla documentazione Qt di THE Q_OBJECT
La macro Q_OBJECT deve apparire nella sezione privata di una definizione di classe che dichiara i propri segnali e slot o che utilizza altri servizi forniti dal sistema meta-oggetto di Qt.
3 Dalla documentazione Qt di moc
Lo strumento moc legge un file di intestazione C ++. Se trova una o più dichiarazioni di classe che contengono la macro Q_OBJECT, produce un file sorgente C ++ contenente il codice meta oggetto per quelle classi. Tra le altre cose, è richiesto il codice meta oggetto per il meccanismo di segnali e slot, le informazioni sul tipo di runtime e il sistema di proprietà dinamico.
4 Dalla documentazione Qt di segnali e slot
La macro Q_OBJECT viene espansa dal preprocessore per dichiarare diverse funzioni membro implementate dal moc; se si verificano errori del compilatore sulla falsariga di "riferimento indefinito a vtable per LcdNumber", probabilmente si è dimenticato di eseguire moc o di includere l'output moc nel comando link.
In gcc -E
puoi vedere le macro espanse. Questo è ciò che si Q_OBJECT
espande in gcc su Linux. Attenzione, questo potrebbe dipendere dalla piattaforma e potrebbe cambiare a seconda della versione di QT. Puoi vedere che non è solo un tag per il compilatore moc.
# 11 "mainwindow.hh"
#pragma GCC diagnostic push
# 11 "mainwindow.hh"
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wsuggest-override"
# 11 "mainwindow.hh"
static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); static inline QString tr(const char *s, cons
t char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } __attribute__ ((__deprecated__)) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } private:
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wattributes"
# 11 "mainwindow.hh"
__attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
# 11 "mainwindow.hh"
#pragma GCC diagnostic pop
# 11 "mainwindow.hh"
struct QPrivateSignal {};
La macro Q_OBJECT deve apparire nella sezione privata di una definizione di classe che dichiara i propri segnali e slot o che utilizza altri servizi forniti dal sistema meta-oggetto di Qt.
Q_OBJECT
macro deve apparire in ogni classe da cui deriva QObject
. Il tuo codice verrà sottilmente rotto quando la macro è assente, e solo perché si compila non lo rende OK.
Q_OBJECT
manca la macro?
Q_OBJECT
, scopriresti che utilizza gli identificatori di accesso. Quindi, se la macro dovrebbe apparire in meno del private
, protected
o public
prescrittori è irrilevante - è solo convenzione per metterlo alla testa della classe.