Оглавление
Использование мета-объектного компилятора (Meta-Object Compiler, moc)Мета-объектный компилятор, moc, - программа, которая обрабатывает расширения C++ от Qt. Инструмент moc читает заголовочный файл C++. Если он находит одно или более объявлений классов, которые содержат макрос Q_OBJECT, то он порождает файл исходного кода C++, содержащий мета-объектный код для этих классов. Кроме всего прочего, мета-объектный код требуется механизму сигналов и слотов, информации о типе времени выполнения и системы динамических свойств. Файл исходного кода C++, сгенерированный moc, должен компилироваться и компоноваться с помощью реализации класса. Если вы используете qmake для создания своих make-файлов, в правила сборки будет включен вызов moc когда это необходимо, поэтому вам не нужно использовать moc непосредственно. Дополнительную информацию по moc смотрите в статье Почему Qt не использует шаблон для сигналов и слотов? ИспользованиеОбычно moc используется с входным файлом, содержащим такое объявление класса: class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = 0); ~MyClass(); signals: void mySignal(); public slots: void mySlot(); }; В дополнение к сигналам и слотам, показанным выше, moc также реализует свойства объекта как в следующем примере. Макрос Q_PROPERTY() объявляет свойство объекта, в то время как Q_ENUMS() объявляет список перечислимых типов внутри класса используемый внутри системы свойств. В следующем примере мы объявляем свойство перечислимого типа Priority, которое также называется priority и имеет функцию получения значения priority() и функцию установки значения setPriority(). class MyClass : public QObject { Q_OBJECT Q_PROPERTY(Priority priority READ priority WRITE setPriority) Q_ENUMS(Priority) public: enum Priority { High, Low, VeryHigh, VeryLow }; MyClass(QObject *parent = 0); ~MyClass(); void setPriority(Priority priority) { m_priority = priority; } Priority priority() const { return m_priority; } private: Priority m_priority; }; Макрос Q_FLAGS() объявляет перечисления, которые используются как флаги, т.е. соединены через ИЛИ. Другой макрос, Q_CLASSINFO(), позволяет вам прикреплять дополнительные пары имя/значение к мета-объекту класса: class MyClass : public QObject { Q_OBJECT Q_CLASSINFO("Author", "Oscar Peterson") Q_CLASSINFO("Status", "Active") public: MyClass(QObject *parent = 0); ~MyClass(); }; Производимый moc вывод должен компилироваться и компоноваться, также как и другой C++ код в вашей программе; в противном случае, сборка завершится ошибкой на последнем этапе компоновки. Если вы используете qmake, это делается автоматически. При каждом запуске qmake производится анализ заголовочных файлов проекта и генерируются make-правила для запуска moc для тех файлов, которые содержат макрос Q_OBJECT. Если объявление класса найдено в файле myclass.h, вывод moc будет помещен в файл с именем moc_myclass.cpp. Этот файл можно затем компилировать обычным образом, получив в результате объектный файл, например в Windows - moc_myclass.obj. Этот объект будет затем включен в список объектных файлов, которые компонуются вместе на последнем этапе сборки программы. Написание make-правил для вызывания mocДля всех программ, за исключением простейших тестовых, рекомендуется автоматизировать запуск moc. Добавляя некоторые правила к make-файлу вашей программы, make может позаботиться о запуске moc, если нужно, и обработке вывода moc. Мы рекомендуем использовать для создания ваших make-файлов инструмент генерации make-файлов qmake. Этот инструмент генерирует make-файл, который выполнит всю необходимую обработку moc. Если вы сами хотите создать make-файлы, то вот несколько советов о том как включить обработку moc. Для объявлений класса Q_OBJECT в заголовочных файлах, здесь есть правило make-файла если используете только GNU make: moc_%.cpp: %.h moc $(DEFINES) $(INCPATH) $< -o $@ Если вы хотите написать переносимый код, вы можете использовать индивидуальные правила следующего вида: moc_foo.cpp: foo.h moc $(DEFINES) $(INCPATH) $< -o $@ Вы также должны помнить для добавления moc_foo.cpp к вашей переменной SOURCES (используйте свое понравившееся имя) и moc_foo.o или moc_foo.obj - к вашей переменной OBJECTS. Оба примера предполагают, что $(DEFINES) и $(INCPATH) расширяются для опций путей определений и включений, которые передаются компилятору C++. Это требуется moc для предварительной обработки исходных файлов. В то время как мы предпочитаем именовать наши файлы исходного кода C++ .cpp, вы можете использовать любые другие расширения, например, .C, .cc, .CC, .cxx и .c++, если вы предпочитаете. Для объявлений класса Q_OBJECT в реализации файлов (.cpp) мы предлагаем такое правило make-файла: foo.o: foo.moc foo.moc: foo.cpp moc $(DEFINES) $(INCPATH) -i $< -o $@ Этим гарантируется, что make запустит moc перед компиляцией foo.cpp. Затем вы можете поместить #include "foo.moc"
в конце foo.cpp, где полностью известны все объявленные в этом файле классы. Опции командной строкиОпции командной строки, поддерживаемые moc:
Вы можете явно указать moc не производить синтаксический разбор частей заголовочного файла. moc определяет идентификатор препроцессора Q_MOC_RUN. Любой код, окружённый конструкцией #ifndef Q_MOC_RUN ... #endif будет пропущен moc'ом. Выявление ошибокmoc предупредит вас о количестве опасных или недопустимых конструкций в объявлениях класса Q_OBJECT. Если вы получили ошибки компоновки на завершающей фазе сборки вашей программы, скажем что YourClass::className() не определен или что в YourClass отсутствует vtable, то что-то сделано неправильно. Очень часто забывают скомпилировать или включить с помощью #include сгенерированный moc код C++, или (в первом случае) включить этот объектный файл в команду компоновки. Если вы используете qmake, попробуйте перезапустить его для обновления вашего make-файла. Будет сделано все, что нужно. Ограниченияmoc не обрабатывает весь C++. Главная проблема - что классы-шаблоны не могут содержать сигналов или слотов. Вот пример: class SomeTemplate<int> : public QFrame { Q_OBJECT ... signals: void mySignal(int); }; Другое ограничение заключается в том, что moc не расширяет макросы, поэтому вы не можете, например, использовать макрос для объявления сигнала/слота или использовать его для объявления базового класса для QObject. Менее значимо, что перечисленные конструкции являются недопустимыми. Все из них имеют альтернативы, которые, мы полагаем, в большинстве случаев являются более подходящими, поэтому удаление этих ограничений для нас не имеет высокого приоритета. Множественное наследование требует указания QObject первымЕсли вы используете множественное наследование, то moc предполагает что первый класс, от которого идет наследование, является подклассом QObject. Также убедитесь, что только первый класс, от которого идет наследование, является QObject. // правильно class SomeClass : public QObject, public OtherClass { ... }; Виртуальное наследование с помощью QObject не поддерживается. Указатели на функцию не могут быть параметрами сигналов и слотовВ большинстве случаев, когда вы обдумываете использование указателей на функцию в качестве параметров сигналов или слотов, мы думаем что наследование является более подходящим вариантом. Вот пример недопустимого синтаксиса: class SomeClass : public QObject { Q_OBJECT public slots: void apply(void (*apply)(List *, void *), char *); // НЕПРАВИЛЬНО }; Вы можете обойти это ограничение, например так: typedef void (*ApplyFunction)(List *, void *); class SomeClass : public QObject { Q_OBJECT public slots: void apply(ApplyFunction, char *); }; Иногда будет даже лучше заменить указатель на функцию наследованием и виртуальными функциями. Перечисления и переименования типов (Typedefs) должны быть полностью уточнены для параметров сигналов и слотовКогда проверяются сигнатуры аргументов, QObject::connect() сравнивает типы данных посимвольно. Соответственно, Alignment и Qt::Alignment будут рассматриваться как два отдельных типа. Чтобы обойти это ограничение убедитесь, что полностью уточнили типы данных когда объявляли сигналы и слоты и когда создавали соединения. Например: class MyClass : public QObject { Q_OBJECT enum Error { ConnectionRefused, RemoteHostClosed, UnknownError }; signals: void stateChanged(MyClass::Error error); }; Тип макросов не может использоваться в качестве параметров для сигналов и слотовТак как moc не расширяет директивы #define, тип макросов, который получает аргумент, не будет работать в сигналах и слотах. Вот некорректный пример: #ifdef ultrix #define SIGNEDNESS(a) unsigned a #else #define SIGNEDNESS(a) a #endif class Whatever : public QObject { Q_OBJECT signals: void someSignal(SIGNEDNESS(int)); }; Макрос без параметров будет работать. Вложенные классы не могут содержать сигналы или слотыВот пример проблемной конструкции: class A { public: class B { Q_OBJECT public slots: // НЕПРАВИЛЬНО void b(); }; }; Возвращаемыми типами сигналов/слотов не могут быть ссылкиСигналы и слоты могут возвращать типы, но возвращаемые ссылки на сигналы или на слоты будут трактоваться как возвращаемое пустое значение (void). Только сигналы и слоты могут появляться в разделах класса signals и slotsmoc будет жаловаться, если вы попытаетесь поместить в разделы класса signals или slots вместо сигналов и слотов другие конструкции. Смотрите также Мета-объектная система, Сигналы и слоты и Система свойств Qt. |
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |