Что делает макрос Q_OBJECT? Зачем всем объектам Qt нужен этот макрос?

132

Я только начал использовать Qt и заметил, что во всех примерах определений классов макрос указан Q_OBJECTв первой строке. Какова цель этого макроса препроцессора?

Тревор Бойд Смит
источник
25
QT относится к QuickTime, а Qt относится к библиотеке C ++ под названием Qt.
Bleadof

Ответы:

133

Из документации Qt :

Компилятор метаобъектов moc - это программа, которая обрабатывает расширения Qt C ++.

Инструмент moc читает файл заголовка C ++. Если он находит одно или несколько объявлений классов, содержащих макрос Q_OBJECT, он создает исходный файл C ++, содержащий мета-объектный код для этих классов. Среди прочего, метаобъектный код требуется для механизма сигналов и слотов, информации о типе времени выполнения и системы динамических свойств.

Сту Макеллар
источник
почему мне нужно не объяснительно писать, Q_OBJECT::connect()а просто connect()?
mLstudent33
19

Он просто сообщает предварительному компилятору, что этот класс имеет элементы графического интерфейса и его нужно запускать через 'moc', вам нужно только добавить это в классы, которые используют механизм сигнала / слота.
Но это будет незаметно игнорироваться в любых других классах - это просто увеличивает время сборки.

Мартин Беккет
источник
3
Также неверно, что он нужен только для классов, использующих механизм сигнал / слот. Отсутствие Q_OBJECTломки qobject_castи самоанализа. Это может привести к некоторому недоумению, так что это плохая идея.
Восстановите Монику
2
Неправда, что Q_OBJECT"незаметно" игнорируется в любых других (не QObject) классах. Согласно стандарту C ++, он вводит неопределенное поведение, объявляя несколько функций-членов и переменных, которые никогда не определяются. Он также загрязняет пространство имен вашего класса определенными QObjectчленами. Например, a Q_OBJECTможет сломать несвязанный класс, который содержит вызываемый метод metaObject.
Восстановить Монику
2
Это неверно. Хотя вы, вероятно, захотите оснастить Q_OBJECTмакросом большинство gui-классов , имеет смысл иметь не-gui-классы с макросом, а также gui-классы без макроса. Макрос полезен, но не ограничивается и не требуется для классов gui.
Pasbi 06
9

MOC (компилятор метаобъектов) преобразует файлы заголовков, включенные в макрос Q_OBJECT, в эквивалентный исходный код C ++. Он в основном управляет механизмом сигнального слота и делает его понятным для компилятора C ++.

адитйа
источник
2
Это неверно: Q_OBJECTмакрос раскрывается компилятором, moc для этого не нужен. Moc ничего не делает с самим макросом, но он генерирует определения переменных-членов и методов, объявленныхQ_OBJECT макросом .
Восстановите Монику
5

1 Из документации Qt системы мета-объектов

Инструмент moc читает исходный файл C ++. Если он обнаруживает одно или несколько объявлений классов, содержащих макрос Q_OBJECT, он создает другой исходный файл C ++, который содержит код метаобъекта для каждого из этих классов. Этот сгенерированный исходный файл либо # включается в исходный файл класса, либо, как правило, компилируется и связывается с реализацией класса.

2 Из Qt документации THE Q_OBJECT

Макрос Q_OBJECT должен появляться в закрытом разделе определения класса, который объявляет свои собственные сигналы и слоты или использует другие сервисы, предоставляемые мета-объектной системой Qt.

3 Из Qt документации moc

Инструмент moc читает файл заголовка C ++. Если он находит одно или несколько объявлений классов, содержащих макрос Q_OBJECT, он создает исходный файл C ++, содержащий мета-объектный код для этих классов. Среди прочего, метаобъектный код требуется для механизма сигналов и слотов, информации о типе времени выполнения и системы динамических свойств.

4 Из документации Qt по сигналам и слотам

Макрос Q_OBJECT расширяется препроцессором, чтобы объявить несколько функций-членов, которые реализованы moc; если вы получаете ошибки компилятора в строках «неопределенная ссылка на vtable для LcdNumber», вы, вероятно, забыли запустить moc или включить вывод moc в команду ссылки.

Боб Чжан
источник
2

В gcc -Eвы можете увидеть расширенные макросы. Это то, что Q_OBJECTрасширяется в gcc в Linux. Имейте в виду, что это может зависеть от платформы и может меняться в зависимости от версии QT. Как видите, это не просто тег для компилятора 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 {};
Arne
источник
0

Макрос Q_OBJECT должен появляться в закрытом разделе определения класса, который объявляет свои собственные сигналы и слоты или использует другие сервисы, предоставляемые мета-объектной системой Qt.

Andres
источник
1
Это вводит в заблуждение: Q_OBJECTмакрос должен присутствовать в каждом производном классе QObject. Ваш код будет слегка нарушен, когда макрос отсутствует, и то, что он скомпилирован, не делает его нормальным.
Восстановить Монику
@KubaOber у вас есть пример кода, который компилируется, но не работает, когда Q_OBJECTмакрос отсутствует?
Крис
2
Если вы посмотрите на реализацию Q_OBJECT, вы обнаружите, что в ней используются спецификаторы доступа. Так ли макрос должен появиться в под private, protectedили publicспецификаторы не имеет никакого отношения - это просто условность , чтобы поместить его в голове класса.
TrebledJ 05