Co robi makro Q_OBJECT? Dlaczego wszystkie obiekty Qt potrzebują tego makra?
132
Właśnie zacząłem używać Qt i zauważyłem, że wszystkie przykładowe definicje klas mają makro Q_OBJECTw pierwszym wierszu. Jaki jest cel tego makra preprocesora?
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.
dlaczego nie muszę pisać wprost, Q_OBJECT::connect()ale po prostu connect()?
mLstudent33
19
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.
Fałszem jest również to, że potrzebujesz go tylko w klasach, które używają mechanizmu sygnału / szczeliny. Brak Q_OBJECTzrywa z qobject_castintrospekcją. Może to prowadzić do pewnych kłopotliwych zachowań, więc to zły pomysł.
Unslander Monica
2
Nie jest prawdą, że Q_OBJECTbę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 QObjectskładnikami specyficznymi -specyficznymi. Np. Q_OBJECTMoże zepsuć niepowiązaną klasę, która tak się składa, że zawiera wywoływaną metodę metaObject.
Unslander Monica
2
To jest źle. Chociaż prawdopodobnie chcesz wyposażyć większość klas gui w Q_OBJECTmakro, 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.
pasbi
8
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 ++
To nieprawda: Q_OBJECTmakro 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_OBJECTmakro .
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.
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.
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.
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 -Emożesz zobaczyć rozwinięte makra. To właśnie Q_OBJECTrozwija 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.
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.
Jest to mylące: Q_OBJECTmakro 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.
Unslander Monica
@KubaOber Czy masz przykład kodu, który kompiluje się, ale nie działa, gdy Q_OBJECTbrakuje makra?
Chris
2
Jeśli spojrzysz na implementację Q_OBJECT, zobaczysz, że używa ona specyfikatorów dostępu. Tak czy makro powinien pojawić się w ramach private, protectedlub publicSpecyfikatory ma znaczenia - to tylko konwencja, aby umieścić go na czele klasy.
Odpowiedzi:
Z dokumentacji Qt :
źródło
Q_OBJECT::connect()
ale po prostuconnect()
?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.
źródło
Q_OBJECT
zrywa zqobject_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 (nieQObject
) 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 klasyQObject
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 ++
źródło
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 przezQ_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.
źródło
W gcc
-E
możesz zobaczyć rozwinięte makra. To właśnieQ_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 {};
źródło
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.
źródło
Q_OBJECT
makro musi występować w każdej klasie, która pochodzi odQObject
. 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 ramachprivate
,protected
lubpublic
Specyfikatory ma znaczenia - to tylko konwencja, aby umieścić go na czele klasy.