Для одного из моих проектов у меня есть дерево производных объектов QObject, которые используют родительскую/дочернюю функциональность QOBJECT для создания дерева.
Это очень полезно, так как я использую сигналы и слоты, используйте защищенные указатели QT и ожидайте родительские объекты удалить дочерние элементы, когда они удалены.
Пока все хорошо. К сожалению, теперь мой проект требует, чтобы я управлял/изменял порядком детей. QObject не обеспечивает средств изменения порядка его детей (исключение: повышение QWIDGET () функция - но это бесполезно в этом случае). Таким образом, теперь я ищу стратегию управления порядком детей. У меня было несколько идей, но я не уверен в их профессионалах и недостатках:
Используйте a int m_orderIndex
членская переменная как ключ сортировки и обеспечивает a sortedChildren()
метод, который возвращает список QObjects, отсортированного по этому ключу.
QObject::children()
метод переопределяется - приведет к проблемам во время циклов, когда порядок объектов изменяется, также является более дорогим, чем реализация по умолчанию.Ведите избыточный список детей в a QList
, и добавьте детей к нему, когда они будут созданы и уничтожены.
Любые идеи или обратная связь, особенно от людей, которые уже решили это в их собственных проектах, высоко ценятся.С Новым годом!
Я потратил много времени, просматривая все эти варианты в последние дни, и тщательно обсудил их с некоторыми другими программистами. Мы решили пойти на вариант A.
Каждый из объектов, которыми мы управляем, является дочерним по отношению к родительскому объекту. Так как Qt не предоставляет никаких средств переупорядочивания этих объектов, мы решили добавить свойство int m_orderIndex
к каждому объекту, которое по умолчанию равно 0.
Каждый объект имеет функцию доступа sortedChildren()
, которая возвращает QObjectList
дочерних объектов. Что мы делаем в этой функции так это:
QObject::chilren()
для получения списка всех доступных дочерних объектов. dynamic_cast
все объекты нашего "базового класса", который предоставляет свойство m_orderIndex
. qSort
с пользовательской функцией LessThan
, чтобы выяснить, нужно ли qSort изменить порядок следования двух объектов. Мы сделали это по следующим причинам:
children()
без необходимости беспокоиться о побочных эффектах. children()
в местах, где порядок не имеет значения, без потери производительности. children()
на sortedChildren()
и получаем желаемый эффект. Одним из хороших моментов в этом подходе является то, что порядок детей не меняется, если все индексы сортировки установлены на ноль.
Извините за ответ на мой собственный вопрос, надеюсь, что это просвещает людей с такой же проблемой. ;)
.У меня нет отдельной опции C, но сравнивая опцию A и B, вы говорите ~4 байта (32-битный указатель, 32-битное целое число) в любом случае, поэтому я бы выбрал опцию B, так как вы можете держать список отсортированным.
Чтобы избежать дополнительной сложности отслеживания детей, вы можете обманывать и держать список отсортированным и опрятным, но комбинировать его с методом sortedChildren, который отфильтровывает всех не-детей. Сложность заключается в том, что этот метод в конце концов обходит O(nlogm) (n = дети, m = элементы списка, предполагая, что m >= n, т.е. дети всегда добавляются), если только у вас нет большого поворота в отношении детей. Вызовем эту опцию C.
Quicksort, в предложенной вами опции A, дает O(n2) (wc), но также требует, чтобы вы получали указатели, трассировали их, возвращали целое число и т.д. Комбинированному методу нужен только список указателей (он должен быть O(n)).
.У меня была такая же проблема, и я решил ее с помощью опции B. Отслеживание не так уж и сложно, просто создайте метод "void addChild(Type *ptr)"; и еще один для удаления дочернего элемента.
Вы не страдаете от злой избыточности, если эксклюзивно храните дочерние элементы в закрытом/публичном детском списке (QList) каждого элемента и опускаете базу QObject. На самом деле, это довольно легко реализовать auto-child-free на свободном (хотя для этого требуется дополнительный указатель родителя).
.Грязный прием: QObject :: children () возвращает ссылку на const. Вы можете отказаться от константности и, таким образом, напрямую манипулировать внутренним списком.
Это довольно зло, и есть риск сделать недействительными итераторы, которые QObject хранит внутри.