Мета-объектная система
Мета-объектная система основана на трёх вещах:
- Класс QObject предоставляет базовый класс для объектов, который могут воспользоваться мета-объектной системой.
- Макрос Q_OBJECT в закрытой секции объявления класса используется для включения возможностей мета-объектов, таких как динамические свойства, сигналы и слоты.
- Мета-объектный компилятор (moc) предоставляет каждому подклассу QObject необходимый код для реализации мета-объектных возможностей.
Инструмент moc читает файл исходных кодов C++. Если он находит один или более объявлений классов, содержащих макрос Q_OBJECT, он производит другой файл исходных кодов C++, который содержит мета-объектный код для каждого из этих классов. Полученный файл исходных кодов или подключается с помощью #include'а в исходном файле класса или, что применяется чаще, компилируется и линкуется вместе с реализацией класса.
В дополнение к предоставляемому механизму сигналов и слотов для коммуникации между объектами (основной причине введения этой системы), мета-объектный код предоставляет следующие дополнительные возможности:
Кроме того, можно выполнить динамическое приведение типа используя qobject_cast() в классах QObject. Функция qobject_cast() ведёт себя аналогично стандартной функции C++ dynamic_cast(), с тем преимуществом, что она не требует поддержки RTTI и работает через границы динамических библиотек. Она пытается привести тип своего аргумента к указателю на тип, указанный в угловых скобках, возвращая ненулевой указатель если объект имеет корректный тип (определяется во время выполнения), или 0 если тип объекта является несовместимым incompatible.
Например, предположим MyWidget унаследован от QWidget и объявлен с макросом Q_OBJECT:
QObject *obj = new MyWidget;
Переменная obj, имеющая тип QObject *, на самом деле ссылается на объект MyWidget, поэтому мы можем соответствующим образом привести её к типу:
QWidget *widget = qobject_cast<QWidget *>(obj);
Приведение типа из QObject к QWidget будет успешным, поскольку объект в действительности - MyWidget, который является подклассом QWidget. Так как мы знаем, что obj - это MyWidget, то мы можем также привести его к типу MyWidget *:
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
Приведение к типу MyWidget будет успешным, поскольку qobject_cast() не делает различий между встроенными типами Qt и пользовательскими типами.
QLabel *label = qobject_cast<QLabel *>(obj);
С другой стороны, приведение к типу QLabel не удалось. Указатель устанавливается равным 0. Это позволяет по-разному обрабатывать объекты разных типов во время выполнения, основываясь на их типе:
if (QLabel *label = qobject_cast<QLabel *>(obj)) {
label->setText(tr("Ping"));
} else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {
button->setText(tr("Pong!"));
}
Хотя можно использовать QObject в качестве базового класса без макроса Q_OBJECT и без мета-объектного кода, ни сигналы, ни слоты, ни другие возможности, описанные выше, не будут доступны если не используется макрос Q_OBJECT. С точки зрения мета-объектной системы, подкласс QObject без мета-объектного кода эквивалентен его ближайшему предку с мета-объектным кодом. Это означает, что например QMetaObject::className() не будет возвращать реальное имя своего класса, а имя класса этого предка.
Поэтому мы настоятельно рекомендуем использование во всех подклассах QObject макроса Q_OBJECT вне зависимости от использования ими сигналов, слотов и свойств.
Смотрите также QMetaObject, Система свойств Qt и Сигналы и слоты.
Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies) |
Торговые марки |
Qt 4.5.3 |
|