Порядок детей QObject (вопрос о стратегии)

Для одного из моих проектов у меня есть дерево производных объектов QObject, которые используют родительскую/дочернюю функциональность QOBJECT для создания дерева.

Это очень полезно, так как я использую сигналы и слоты, используйте защищенные указатели QT и ожидайте родительские объекты удалить дочерние элементы, когда они удалены.

Пока все хорошо. К сожалению, теперь мой проект требует, чтобы я управлял/изменял порядком детей. QObject не обеспечивает средств изменения порядка его детей (исключение: повышение QWIDGET () функция - но это бесполезно в этом случае). Таким образом, теперь я ищу стратегию управления порядком детей. У меня было несколько идей, но я не уверен в их профессионалах и недостатках:



Опция A: Пользовательская индексная членская переменная вида

Используйте a int m_orderIndex членская переменная как ключ сортировки и обеспечивает a sortedChildren() метод, который возвращает список QObjects, отсортированного по этому ключу.

  • Легкий реализовать в существующую структуру объекта.
  • Проблематичный, когда QObject::children() метод переопределяется - приведет к проблемам во время циклов, когда порядок объектов изменяется, также является более дорогим, чем реализация по умолчанию.
  • Должен отступить к порядку объектов QObject, если все ключи сортировки равны или 0/значение по умолчанию.

Опция B: Избыточный список детей

Ведите избыточный список детей в a QList, и добавьте детей к нему, когда они будут созданы и уничтожены.

  • Требует дорогого отслеживания добавленных / удаленных объектов. Это в основном приводит к второму дочернему/родительскому отслеживанию и партии сигналов/слотов. QObject внутренне уже делает все это, таким образом, это не могла бы быть хорошая идея сделать это снова. Также чувствует, что много чрезмерного увеличения размера добавляется для простой вещи как изменение порядка детей.
  • Хорошая гибкость, так как QList детей может быть изменен по мере необходимости.
  • Позволяет ребенку быть в QList больше чем один раз, или нисколько (даже при том, что это мог бы быть все еще ребенок QObject),

Опция C:...?

Любые идеи или обратная связь, особенно от людей, которые уже решили это в их собственных проектах, высоко ценятся.С Новым годом!

6
задан BastiBen 2 January 2010 в 14:45
поделиться

4 ответа

Я потратил много времени, просматривая все эти варианты в последние дни, и тщательно обсудил их с некоторыми другими программистами. Мы решили пойти на вариант A.

Каждый из объектов, которыми мы управляем, является дочерним по отношению к родительскому объекту. Так как Qt не предоставляет никаких средств переупорядочивания этих объектов, мы решили добавить свойство int m_orderIndex к каждому объекту, которое по умолчанию равно 0.

Каждый объект имеет функцию доступа sortedChildren(), которая возвращает QObjectList дочерних объектов. Что мы делаем в этой функции так это:

  1. Используем обычную функцию QObject::chilren() для получения списка всех доступных дочерних объектов.
  2. dynamic_cast все объекты нашего "базового класса", который предоставляет свойство m_orderIndex.
  3. Если объект является кассируемым, добавьте его во временный список объектов.
  4. используйте qSort с пользовательской функцией LessThan, чтобы выяснить, нужно ли qSort изменить порядок следования двух объектов.
  5. Верните список временных объектов.

Мы сделали это по следующим причинам:

  • Существующий код (особенно собственный код Qt) может продолжать использовать children() без необходимости беспокоиться о побочных эффектах.
  • Мы можем использовать обычную функцию children() в местах, где порядок не имеет значения, без потери производительности.
  • В местах, где нам нужен упорядоченный список детей, мы просто заменяем children() на sortedChildren() и получаем желаемый эффект.

Одним из хороших моментов в этом подходе является то, что порядок детей не меняется, если все индексы сортировки установлены на ноль.

Извините за ответ на мой собственный вопрос, надеюсь, что это просвещает людей с такой же проблемой. ;)

.
7
ответ дан 16 December 2019 в 21:41
поделиться

У меня нет отдельной опции C, но сравнивая опцию A и B, вы говорите ~4 байта (32-битный указатель, 32-битное целое число) в любом случае, поэтому я бы выбрал опцию B, так как вы можете держать список отсортированным.

Чтобы избежать дополнительной сложности отслеживания детей, вы можете обманывать и держать список отсортированным и опрятным, но комбинировать его с методом sortedChildren, который отфильтровывает всех не-детей. Сложность заключается в том, что этот метод в конце концов обходит O(nlogm) (n = дети, m = элементы списка, предполагая, что m >= n, т.е. дети всегда добавляются), если только у вас нет большого поворота в отношении детей. Вызовем эту опцию C.

Quicksort, в предложенной вами опции A, дает O(n2) (wc), но также требует, чтобы вы получали указатели, трассировали их, возвращали целое число и т.д. Комбинированному методу нужен только список указателей (он должен быть O(n)).

.
0
ответ дан 16 December 2019 в 21:41
поделиться

У меня была такая же проблема, и я решил ее с помощью опции B. Отслеживание не так уж и сложно, просто создайте метод "void addChild(Type *ptr)"; и еще один для удаления дочернего элемента.

Вы не страдаете от злой избыточности, если эксклюзивно храните дочерние элементы в закрытом/публичном детском списке (QList) каждого элемента и опускаете базу QObject. На самом деле, это довольно легко реализовать auto-child-free на свободном (хотя для этого требуется дополнительный указатель родителя).

.
0
ответ дан 16 December 2019 в 21:41
поделиться

Грязный прием: QObject :: children () возвращает ссылку на const. Вы можете отказаться от константности и, таким образом, напрямую манипулировать внутренним списком.

Это довольно зло, и есть риск сделать недействительными итераторы, которые QObject хранит внутри.

0
ответ дан 16 December 2019 в 21:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: