Иерархия объектов Qt часть 2
Здравствуйте, уважаемые читатели. Эта статья является продолжением предыдущей, и я как обещал, расскажу в ней о приведение типов и объединении объектов в иерархии.
Иерархии объектов
И так начнем. Конструктор класса QObject имеет вид QObject(QObject* parent = 0). Perent это указатель на родительский объект. Если вместо этого параметра передать ноль или просто игнорировать его, что позволяет сделать объявление по умолчанию, то этот объект будет стоять в вершине иерархии. В последствии родительский объект всегда можно изменить методом setParent(). Практическая выгода в использовании иерархий объектов заключается в автоматической очистке памяти, которую обеспечивает QObject путем удаления всех дочерних объектов. Объектам так же можно задавать имена при создании. По умолчанию при создании объекта он имеет, пустую строку на месте имени. Имя объекта не имеет никакого значения с точки зрения приложения, оно может быть полезно только разработчику в целях отладки и т.д.
Например:
//Создаем верхний объект иерархии
QObject* object1 = new QObject;
// object2 будет дочерним по отношению к object1
QObject* object2 = new QObject(object1);
// object3 будет дочерним по отношению к object2
QObject* object3 = new QObject(object2);
object1->setObjectName(“Main object”);
object2->setObjectName(“Child of object1”);
object3->setObjectName(“Child of object2”);
В результате у нас получилась такая иерархия:
object1 -> object2 -> object3
При уничтожении object1 тот уничтожит object2, что повлечет за собой уничтожение object3. Такая рекурсивная очистка значительно упрощает жизнь при программировании на таких языках как С++. Но у этого есть и обратная сторона медали, мы должны создавать все объекты динамически, при помощи оператора new иначе будут ошибки времени выполнения в следствие двух попыток удаления объекта. Это нужно взять за правило. Не динамически можно создавать только объекты, находящиеся в вершине иерархии.
Например:
QObject parent;
QObject* child = new QObject(&parent);
Этот код сработает верно. Компилятор удалит переменную parent при выходе из области видимости, а parent удалит child.
Для того, что бы мы могли ориентироваться в иерархии объектов, QObject предоставляет нам два метода. parent() и children(). Метод parent() вернет указатель на родительский объект или 0, если объект стоит на вершине, метод children() вернет константный указатель на список дочерних объектов.
Например:
QObject parent;
QObject* child1 = new QObject(&parent);
child1->setObjectName(“child1”);
QObject* child2 = new QObject(child1);
child2->setObjectName(“child2”);
//Выводим имена объектов
for (QObject* ptr = child2; ptr; ptr = ptr->parent()) {
qDebug()<< ptr->objectName();
}
Примечание для пользователей Windows: Для того, что бы видеть в консоли вывод функции qDebug() вам нужно добавить в файл проекта следующую строку: CONFIG += console.
Мы так же можем производить поиск по имени объекта в иерархии при помощи метода findChild(). Эта функция не будет работать в MSVC6, вместо нее придется использовать функцию qFindChild().
Например:
// Получаем указатель на child1
QObject* child1Ptr = parent.findChild(“child1”);
Мы так же можем воспользоваться расширенным рекурсивным поиском при помощи метода findChildren(). Если при вызове метода не передать ему аргумент, он вернет список дочерних объектов. Аргументом может быть строка или регулярное выражение (о них и о средствах их поддержки в Qt поговорим в одной из следующих статей).
Например:
QList<QObject*> list = parent.findChildren(QRegExp(“ch*”));
Оговорюсь, что этот метод то же не работает в MSVC6, вместо него нужно использовать функцию qFindChildren(). Так же в целях отладки может оказаться полезной функция dumpObjectTree() призванная отображать объекты потомки в виде иерархии. Например ее вывод может быть таким:
QObject::
QObject::child1
QObject::child2
Приведение типов
В этой части статьи мы рассмотрим две связных темы: метаинформацию и основанный на ней оператор приведения типов. Для приведения типов Qt предоставляет шаблон qobject_cast<T>() для классов унаследованных от QObject. Эта функция базируется на метаинформации создаваемой препроцессором MOC. Что такое мета объектная информация? Это набор данных о классе, сигналах и слотах (в том числе и указатели на них) и т.д. В Qt эти данные представлены классом QMetaObject. Для того, что бы получить доступ к мета данным объекта унаследованного от QObject нужно вызвать его метод metaObject(). Для того, что бы узнать объект производного класса можно сделать так:
QObject* object = new QPushButton;
qDebug()<<object->metaObject()->className();
В результате на консоль будет выведена строка “QPushButton”.
Мы так же можем проверить производный класс методом inherits():
QPushButton* button = new QPushButton;
//На консоль выведется true
qDebug()<<button->inherits(“QPushButton”);
//На консоль выведется false
qDebug()<<button->inherits(“QTimer”);
За более подробной информацией отсылаю читателя к документации по его версии Qt. В следующих статьях мы начнем рассматривать библиотеку контейнеров Qt, строки и регулярные выражения.