Właśnie zacząłem używać Qt i zauważyłem, że wszystkie przykładowe definicje klas mają makro Q_OBJECT
w pierwszym wierszu. Jaki jest cel tego makra preprocesora?
Właśnie zacząłem używać Qt i zauważyłem, że wszystkie przykładowe definicje klas mają makro Q_OBJECT
w pierwszym wierszu. Jaki jest cel tego makra preprocesora?
Odpowiedzi:
Z dokumentacji Qt :
Meta-Object Compiler, moc, to program obsługujący rozszerzenia Qt w języku C ++.
Narzędzie moc odczytuje plik nagłówkowy C ++. Jeśli znajdzie jedną lub więcej deklaracji klas, które zawierają makro Q_OBJECT, tworzy plik źródłowy C ++ zawierający kod meta-obiektu dla tych klas. Między innymi kod meta-obiektowy jest wymagany dla mechanizmu sygnałów i szczelin, informacji o typie czasu wykonywania i dynamicznego systemu właściwości.
Q_OBJECT::connect()
ale po prostu connect()
?
Po prostu mówi prekompilatorowi, że ta klasa ma elementy gui i musi zostać uruchomiona przez 'moc', którą wystarczy dodać do klas, które używają mechanizmu signal / slot.
Ale będzie po cichu zignorowany w innych klasach - po prostu wydłuża czas kompilacji.
Q_OBJECT
zrywa z qobject_cast
introspekcją. Może to prowadzić do pewnych kłopotliwych zachowań, więc to zły pomysł.
Q_OBJECT
będzie on „po cichu” ignorowany w innych (nie QObject
) klasach. Zgodnie ze standardem C ++ wprowadza niezdefiniowane zachowanie, deklarując kilka funkcji składowych i zmiennych, które nigdy nie zostały zdefiniowane. Zanieczyszcza również przestrzeń nazw twojej klasy QObject
składnikami specyficznymi -specyficznymi. Np. Q_OBJECT
Może zepsuć niepowiązaną klasę, która tak się składa, że zawiera wywoływaną metodę metaObject
.
Q_OBJECT
makro, to całkowicie sensowne jest posiadanie klas innych niż gui z makrem, a także klas gui bez makra. Makro jest przydatne, ale nie jest ograniczone ani wymagane dla klas gui.
MOC (kompilator meta obiektu) konwertuje pliki nagłówkowe zawarte w makrze Q_OBJECT na kod źródłowy odpowiadający C ++. Zasadniczo kontroluje mechanizm slotu sygnału i czyni go zrozumiałym dla kompilatora C ++
Q_OBJECT
makro jest rozwijane przez kompilator, moc nie jest do tego potrzebna. Moc nie robi nic z samym makrem, ale generuje definicje zmiennych składowych i metod zadeklarowanych przez Q_OBJECT
makro .
1 Z dokumentacji Qt systemu meta-obiektów
Narzędzie moc odczytuje plik źródłowy C ++. Jeśli znajdzie jedną lub więcej deklaracji klas, które zawierają makro Q_OBJECT, tworzy inny plik źródłowy C ++, który zawiera kod meta-obiektu dla każdej z tych klas. Ten wygenerowany plik źródłowy jest # dołączany do pliku źródłowego klasy lub, częściej, skompilowany i połączony z implementacją klasy.
2 Z dokumentacji Qt Q_OBJECT
Makro Q_OBJECT musi pojawić się w prywatnej sekcji definicji klasy, która deklaruje własne sygnały i sloty lub korzysta z innych usług dostarczanych przez system meta-obiektów Qt.
3 Z dokumentacji Qt MOC
Narzędzie moc odczytuje plik nagłówkowy C ++. Jeśli znajdzie jedną lub więcej deklaracji klas, które zawierają makro Q_OBJECT, tworzy plik źródłowy C ++ zawierający kod meta-obiektu dla tych klas. Między innymi kod meta-obiektowy jest wymagany dla mechanizmu sygnałów i szczelin, informacji o typie czasu wykonywania i dynamicznego systemu właściwości.
4 Z dokumentacji Qt sygnałów i gniazd
Makro Q_OBJECT jest rozszerzane przez preprocesor w celu zadeklarowania kilku funkcji składowych, które są implementowane przez moc; jeśli otrzymujesz błędy kompilatora w postaci „niezdefiniowanego odwołania do vtable dla LcdNumber”, prawdopodobnie zapomniałeś uruchomić moc lub dołączyć wyjście moc do polecenia link.
W gcc -E
możesz zobaczyć rozwinięte makra. To właśnie Q_OBJECT
rozwija się w gcc w systemie Linux. Należy pamiętać, że może to zależeć od platformy i może ulec zmianie w zależności od wersji QT. Jak widać, to nie jest tylko tag dla kompilatora 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 {};
Makro Q_OBJECT musi pojawić się w prywatnej sekcji definicji klasy, która deklaruje własne sygnały i sloty lub korzysta z innych usług dostarczanych przez system meta-obiektów Qt.
Q_OBJECT
makro musi występować w każdej klasie, która pochodzi od QObject
. Twój kod zostanie subtelnie uszkodzony, gdy makro jest nieobecne, a sam fakt kompilacji nie oznacza, że wszystko jest w porządku.
Q_OBJECT
brakuje makra?
Q_OBJECT
, zobaczysz, że używa ona specyfikatorów dostępu. Tak czy makro powinien pojawić się w ramach private
, protected
lub public
Specyfikatory ma znaczenia - to tylko konwencja, aby umieścić go na czele klasy.