Russian Qt Forum
Апрель 28, 2024, 18:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 3 [4] 5 6   Вниз
  Печать  
Автор Тема: Деревянный айтем  (Прочитано 30229 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #45 : Январь 11, 2019, 07:42 »

Еще раз - вам надо несколько графов.
Ну как-то я не оценил (концептуальной) глубины этого совета Улыбающийся В самом деле, что из этого следует? Вот есть некая зависимость, что с ней делать? Давайте в классе заведем указатель "на кого ссылаемся". А на др стороне вероятно массив "тех кто на меня ссылается". И будем отслеживать это там и сям (список выше). А еще зависимость - повторить. Ну оно сейчас так примерно и сделано, и это изрядно загрязняет рабочие классы и undo. Или я чего-то не понял?

Написал неск тестов, пока проблем не испытал. Обдумываю как это "ляжет". Вот (пока) один случай где нужно больше ф-ционала: связка содержит данные (контейнер). Напрашивается добавить это в класс дуги, напр
Код
C++ (Qt)
struct CGraphArc {
 ...
 TArcType m_type;            // тип зависимости
 CGraphNode * m_node;   // второй нод (первый - владелец этой CGraphArc)
 CArcData * m_data;        // ??? данные дуги/связки
};
 
Чем это плохо/чревато? Какие есть еще возможности ?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #46 : Январь 15, 2019, 14:06 »

Для копирования можно решить задачу через ID.
В скопированной структуре все ID копий дополняем суффиксом "_Copy" (например), попутно запоняя мапу <ID : pointer>.
Затем пробегаемся по ним ещё раз и подставляем соответствующие новым ID значения указателей.

ЗЫ. "я так делал, оно работаеть" Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #47 : Январь 16, 2019, 13:46 »

Для копирования можно решить задачу через ID.
В скопированной структуре все ID копий дополняем суффиксом "_Copy" (например), попутно запоняя мапу <ID : pointer>.
Затем пробегаемся по ним ещё раз и подставляем соответствующие новым ID значения указателей.

ЗЫ. "я так делал, оно работаеть" Улыбающийся
Не очень понял причем здесь ID. Ладно, попробую еще раз направить обсуждение в нужное русло (куда оно идти упорно не хочет  Улыбающийся)

Вот есть структура стартового поста (там правда маленько насвистел, правильно QList вместо QVector, айтемы должны быть не перемещаемы). Нужен член m_parent (хотя бы для удаления айтем). Выясняется что каких-то чудесных средств для автоматычной поддержки члена m_parent нема - лучше всего запретить копирование и передавать указатель как аргумент во все методы требующие его установки. В этом нет ничего плохого.

Хорошо, теперь возникает простая мысль - а не сделать ли это в общем виде, напр базовый класс хранящий 2 контейнера (связки "на кого ссылаюсь я" и "кто ссылается на меня"). Тогда структура "дерево"(по сути айтем дерева) просто не нужна - она покрывается базовым классом. А если идентифицировать связки, то один айтем (содержательные данные) могут храниться в N различных деревьях. А по жизни часто собсно "дерева" и нет как такового - зависимость часто вырождается в примитивное "объект A зависит от объекта B" - но это тоже надо поддерживать, и это не так уж дешево.

Правда и в этом случае радости "просто копирования" недоступны - надо что-то решать со связками копий (точнее клонов). Я вижу такой вариант - создать мапу "кто в кого скопировался", и потом корректировать первый контейнер ("на кого ссылаюсь я" ну или контейнер парентов)

- если скопировался и парент и чайлд - создаем новую связку
- если скопировался только чайлд - связываем его со старым парентом

Вот все, прошу излагать свои мысли
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #48 : Январь 16, 2019, 15:31 »

Я что имею в виду: например у нас есть объекты А, B, C. Пусть B и C - дети А, тогда имеем такой псевдо-код:

A{name = "Item.A", m_parent = NULL, childs = {B,C} };
B{name = "Item.B", m_parent = &A, childs = {B,C} };
C{name = "Item.C", m_parent = &A, childs = {NULL} };

Теперь мы скопипастили наш А (допустим), после вставки у нас стало:

// это оригиналы:
A{name = "Item.A", m_parent = NULL, childs = {B,C} };
B{name = "Item.B", m_parent = &A, childs = {B,C} };
C{name = "Item.C", m_parent = &A, childs = {NULL} };

// а это копии:
A1 {name = "Item.A", m_parent = NULL, childs = {B,C} };
B1 {name = "Item.B", m_parent = &A, childs = {B,C} };
C1 {name = "Item.C", m_parent = &A, childs = {NULL} };

То есть копии до сих пор ссылаются на оригиналы, тем самым херя всю иерархию. И надо бы это сделать "правильно", в этом задача?
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #49 : Январь 17, 2019, 11:39 »

То есть копии до сих пор ссылаются на оригиналы, тем самым херя всю иерархию. И надо бы это сделать "правильно", в этом задача?
Да, точнее "и в этом тоже" (обсуждение др аспектов общей конструкции тоже приветствуется). Ладно, поехали с копированием. Наверное Вы имели ввиду
Код:
// а это копии:
A1 {name = "Item.A", m_parent = NULL, childs = {&B,&C} };
B1 {name = "Item.B", m_parent = &A, childs = {NULL} };
C1 {name = "Item.C", m_parent = &A, childs = {NULL} };
Напрашивается такое решение: создать мапу/хеш "кто в кого скопировался", т.е.
Код:
{ { A, A1 }, { B, B1 }, { C, C1 } }
Паренты и чайлды копий изначально пустые. Теперь пробегаемся по хешу, псевдокод
Код
C++ (Qt)
void SetLinks( const Hash & hash )
{
  for (iter it = hash.begin(); it != hash.end(); ++it) {
    Node * src = it.key();
    Node * dst = it.value();
    dst->m_parent = hash.value(src->m_parent);   // пробуем установить копию парента
    if (!dst->m_parent)
      dst->m_parent = src->m_parent;   // иначе копия получает того же парента что и оригинал
 
    if (dst->m_parent)
      dst->m_parent->AddChild(dst);      // добавляем чайлда
  }
}
 
Выглядит разумно и просто, но тут 2 момента

1) Явная ошибка: копии могут получать новых чайлдов в другом порядке, напр
Цитировать
A1 {name = "Item.A", m_parent = NULL, childs = {&С1,&B1} };
(прекрасная мелкая пакость  Улыбающийся)

2) Не совсем ясно а как же заполучить хеш - вероятно придется создавать вектор всех копируемых и создавать копии/клоны эл-т за эл-том. Это не так уж страшно, но
Код
C++ (Qt)
СTreeItem * dst = src->Clone(parent);
Интуитивно (или стандартно) ожидается что будет скопирована вся ветка дерева (рекурсивный вызов Clone). Но тогда в какой момент пробегаться по хешу (и как его накопить) ?

Мда, все не так уж просто  Улыбающийся
« Последнее редактирование: Январь 17, 2019, 11:44 от Igors » Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #50 : Январь 17, 2019, 12:42 »

Если рекурсия, то еще проще можно.
Поскольку в метод клонирования передается новый родитель, сразу назначаем его "детям".
Соответстенно родитель знает, каких детей он склонировал, он же должен занести их в свой список "детей" и так по цепочке Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #51 : Январь 18, 2019, 11:09 »

Если рекурсия, то еще проще можно.
Поскольку в метод клонирования передается новый родитель, сразу назначаем его "детям".
Соответстенно родитель знает, каких детей он склонировал, он же должен занести их в свой список "детей" и так по цепочке Улыбающийся
Все так, но здесь протаскивается предположение что "парент владеет чайлдами" (значит и отвечает за их клонирование). А вот более общий случай

- сами айтемы помещены в контейнер (напр QList) который ими и владеет. Но айтемы еще и связаны в дерево (а может и не одно). Юзеру выбирает "вьюху" (как здесь говорят) где айтемы показаны или по порядку в контейнере (flat) или в виде дерева (hierarchy) или еще как. Вот какие-то айтемы выбраны и жмется бубочка "duplicate". Наши действия?
Записан
Авварон
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 3258


Просмотр профиля
« Ответ #52 : Январь 18, 2019, 11:59 »

Наши действия?

Ну все как обычно, вы недоговоариваете. Для простоты возьмем один айтем (А). Им владеет айтем Б. И он "смотрит" на айтем В.
Копируем айтем А1. Что должно произойти?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #53 : Январь 18, 2019, 12:47 »

Для простоты возьмем один айтем (А). Им владеет айтем Б. И он "смотрит" на айтем В.
Копируем айтем А1. Что должно произойти?
Пусть копируется только A->A1. Тогда копия должна ссылаться на имеющиеся Б и В. Если же и они копировались, то копия должна ссылаться на Б1 и/или В1. К этому можно придраться, но другого разумного поведения я не вижу.

Как уже не раз говорилось, "владение" здесь ни при чем. Оно всего лишь означает что разрыв связи должен сопровождаться удалением ссылающегося. Что кстати не уникально, напр айтемы связаны в 2 или более деревьев, любое может удалять, почему нет?
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #54 : Январь 18, 2019, 16:37 »

Как уже не раз говорилось, "владение" здесь ни при чем. Оно всего лишь означает что разрыв связи должен сопровождаться удалением ссылающегося. Что кстати не уникально, напр айтемы связаны в 2 или более деревьев, любое может удалять, почему нет?

Вы все время смешиваете два вида сущностей в одно целое.

Есть данные D1, D2, D3, временем жизни которых что-то управляет (или другими словами владеет). Это может быть общий менеджер данных или узлы контейнера (списка, дерева или др.).

Узлами контейнера N1, N2 и т.п. уникально владеет (управляет временем жизни) сам контейнер. Узлы одного контейнера не являются одновременно узлами другого.
Что касается данных D, то реализуется связь [1..1], то есть одному элементу данных Di всегда соответствует один узел Ni.
Если предполагается, что узлы управляют временем жизни данных (владеют), то можно говорить о композиции (уникальной агрегации) данных узлами.
Если предполагается, что узлы не управляют временем жизни данных (данными владеет некий внешний менеджер), то можно говорить об ассоциации данных узлам.
Но, и в том и другом случае при копировании узлов, данные тоже копируются.

Что-такое данные и какими свойствами они обладают - обобщенные (shared), неявно обобщенные (copy-on-write), единичные или в виде контейнера (мультипликативность) и т.п. решается в контексте конкретной задачи.

Например, есть данные MyStruct
- если не требуется обобщение данных, то в качестве D используем MyStruct, ::std::unique_ptr<MyStruct> или др.
- если требуется обобщение данных, то в качестве D используем SharedWrapper<MyStruct>, QSharedPointer<MyStruct>, ::std::shared_ptr<MyStruct> или др.
- если требуется неявное обобщение данных, то в качестве D используем ImplicitSharedWrapper<MyStruct> или др.

Второе, не следует смешивать две совершенно разных вещи - контейнер Tree и отношение Parent-Child.

Отношение Parent-Child подразумевает, что Parent управляет временем жизни (владеет) Child, при этом Child композитно агрегируется в Parent (уникально владеет).
Parent может содержать 0, 1 .. N элементов Child в любом представлении (упорядоченно/не упорядочено, в виде отображения или еще чего нибудь).
Обычно подразумевается, что Child имеет ассоциативную связь с Parent, хотя это не обязательно.
Удаление Parent влечет за собой удаление всех Child. Копирование Parent - копирование всех Child.

Отношение Parent-Child может быть реализовано без всякого обобщающего контейнера Tree.

В случае наличия контейнера Tree, он полностью владеет своими узлами, и, как частный случай возможной реализации, отношение узлов N в контейнере Tree может быть реализовано в виде отношения Parent-Child.
При этом сам контейнер композитно агрегирует корневой Parent (обычно называют root).
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #55 : Январь 19, 2019, 09:17 »

Второе, не следует смешивать две совершенно разных вещи - контейнер Tree и отношение Parent-Child.
Ну "совершенно разные" - явный перегиб, "дерево" по существу и есть утверждение зависимости парент-чайлд. Но согласен что это "не одно и то же", чайлды необязательно удаляются/копируются вместе с парентом (как это часто подразумевается).

Это злосчастное "владение" все время уводит в сторону. Предлагаю считать что "владелец" - просто контейнер всех объектов (напр QList) в порядке их создания, и хранятся указатели т.е. объекты неперемещаемы.

Например, есть данные MyStruct
- если не требуется обобщение данных, то в качестве D используем MyStruct, ::std::unique_ptr<MyStruct> или др.
- если требуется обобщение данных, то в качестве D используем SharedWrapper<MyStruct>, QSharedPointer<MyStruct>, ::std::shared_ptr<MyStruct> или др.
- если требуется неявное обобщение данных, то в качестве D используем ImplicitSharedWrapper<MyStruct> или др.
Не понял о каком (неявном) обобщении Вы говорите? Вот пользователю предъявлен список объектов в режиме "by hierarchy", т.е. он может линковать один объект к другому. Теперь он переключился напр в режим "by master material", тоже иерархия/дерево но никак не связанная с предыдущим, т.е. объекты те же но зависимости между ними совсем другие. Что предлагаете? Рисовать структуры для каждого случая (навскидку насчитаю десяток). Или все-таки попробовать как-то обобщить? И ничего я не "путаю"
Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #56 : Январь 19, 2019, 22:10 »

Ну "совершенно разные" - явный перегиб, "дерево" по существу и есть утверждение зависимости парент-чайлд. Но согласен что это "не одно и то же", чайлды необязательно удаляются/копируются вместе с парентом (как это часто подразумевается).

Конкретная реализация "дерева" не обязательно построена на зависимости "парент-чайлд".
Можно, например, "дерево" внутри реализовать с помощью обычного отображения {key, value}, где в качестве ключа использовать пару {номер уровня, номер позиции на уровне}. Внешний интерфейс при этом ни чем не будет отличаться от "дерева", реализованного с помощью "парент-чайлд".

Это злосчастное "владение" все время уводит в сторону. Предлагаю считать что "владелец" - просто контейнер всех объектов (напр QList) в порядке их создания, и хранятся указатели т.е. объекты неперемещаемы.

"Владение" в рамках объектно ориентированной модели правильнее называть ассоциативной связью агрегации. Если в объектной модели не определить кто-кого-каким способом агрегирует (другими словами, кто-кем-как владеет), с учетом правил непротиворечивости самой модели, то никогда не получится корректное программное решение.

Для отношения "парент-чайлд" общепринятая объектная модель определена однозначно, как описано мной ранее.
Цитировать
Отношение Parent-Child подразумевает, что Parent управляет временем жизни (владеет) Child, при этом Child композитно агрегируется в Parent (уникально владеет).
Это, можно сказать, определение этого отношения. Другая модель уже не реализует отношение "парент-чайлд", а реализует что-то ещё.

Не понял о каком (неявном) обобщении Вы говорите?

Неявное обобщение (implicit-shared) используется в частности для реализации механизма copy-on-write, когда фактическое копирование данных происходит в момент обращения к ним для изменения. То есть фактически используется обобщение данных, но реализуется поведение уникального владения (композитного агрегирования).

Вот пользователю предъявлен список объектов в режиме "by hierarchy", т.е. он может линковать один объект к другому. Теперь он переключился напр в режим "by master material", тоже иерархия/дерево но никак не связанная с предыдущим, т.е. объекты те же но зависимости между ними совсем другие. Что предлагаете? Рисовать структуры для каждого случая (навскидку насчитаю десяток). Или все-таки попробовать как-то обобщить? И ничего я не "путаю"

В этом описании реализуемая модель может выглядеть так:
- Существует общий менеджер ресурсов в виде неупорядоченного их множества. Именно этот менеджер "уникально владеет" (композитно агрегирует) ресурсами.
- Существует набор деревьев "by hierarchy", "by master material" и т.п., содержащий в узлах данные с ассоциативным связями (ссылками или не владеющими указателями) на ресурсы.

Либо без общего менеджера ресурсов:
- Существует набор деревьев "by hierarchy", "by master material" и т.п., содержащий в узлах данные, которые "совместно владеют" (обобщенно агрегируют) ресурсы.

То есть в деревья складываются не сами ресурсы, а данные, которые определяют вид ассоциативных связей с ресурсами.
При этом и в том и другом случае данные могут обладать еще и дополнительными уникальными атрибутами, если это необходимо.
Само понятие "дерева" следует реализовать в виде шаблона, узлы которого композитно агрегируют (уникально владеют) данными. Тип данных является параметром шаблона.
« Последнее редактирование: Январь 19, 2019, 22:13 от ssoft » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #57 : Январь 20, 2019, 13:47 »

"Владение" в рамках объектно ориентированной модели правильнее называть ассоциативной связью агрегации. Если в объектной модели не определить кто-кого-каким способом агрегирует (другими словами, кто-кем-как владеет), с учетом правил непротиворечивости самой модели, то никогда не получится корректное программное решение.
Ну ладно, давайте о владении (толку все равно нет).

Вот есть 3D сцена в которую юзверь добавляет 3D объекты, напр модели, камеры, источники света и.т.п. Кто "владеет" этими объектами? Наверное академически правильно сказать: класс "сцена", но можно и по-простому: "контейнер объектов". Отношения между объектами  могут быть самыми разнообразными и выражаться самым разным ф-ционалом, как раз проблема в том что этих отношений очень много. Но с "владением" они никак не связаны - объект либо существует в сцене - либо нет, и значит он сам удален. Вот и все

Тот же пример: отношение "иерархия" (парент-чайлд) визуализировано в виде дерева. Да, удаление/копирование парента применяется ко всем его чайлдам, но это же вовсе не значит что "парент владеет чайлдом" - просто он может (или имеет право) удалять/копировать объекты сцены. Какое-то другое отношение тоже может это делать, или наоборот, та же иерархия может не удалять чайлдво а лишь отлинковывать его от удаляемого парента. Напр сцена должна иметь хотя бы одну камеру, она может быть чьим-то чайлдом (почему нет), но мочить эту камеру нельзя (если не осталось других).

Как видите, вопрос "владения" для объектов верхнего уровня не стоит выеденного яйца. С ним давным-давно все ясно (объектами владеет сцена), и постоянно скатываясь во "владение" мы только толчем воду в ступе.

То есть в деревья складываются не сами ресурсы, а данные, которые определяют вид ассоциативных связей с ресурсами.
При этом и в том и другом случае данные могут обладать еще и дополнительными уникальными атрибутами, если это необходимо.
Так вот об этом я и хочу поговорить, а Вы все "владение" да "владение"  Улыбающийся

Дерево предполагает что нод имеет одного (и только одного) парента. Это так в подавляющем большинстве случаев, но все же не всегда. Пример: объекты типа Bone (кости, по-простому отрезок или точка) управляют полигонной моделью, как правило к модели линкуется 100 и более костей. Но никто не мешает прилинковать ту же кость(и) к др модели(ям). "Только один парент" здесь никак не выходит. Поэтому все-таки граф (не пойму чем это совершенно безобидное слово так ранит любителей std  Улыбающийся)

Само понятие "дерева" следует реализовать в виде шаблона, узлы которого композитно агрегируют (уникально владеют) данными. Тип данных является параметром шаблона.
Понял так что, мол, template - это признак грамотности, давайте совать его везде. Но не вижу как (или чем) он здесь поможет. Все 3D объекты унаследованы от базового класса, напрашивается добавить менеджер ссылок к нему. Но меня почему-то упорно тянет сделать этот менеджер внешним классом (хешем), напр
Код:
QHash<BaseClass *, CGraphNode> theReferenceHash;
Все-таки пробежка по всем ссылкам (хотя бы их дебаг печать и I/O) - ценная возможность, да и далеко не каждый объект имеет ссылки/связи. Или даже вот так, вызывающе
Код:
QHash<void *, CGraphNode> theReferenceHash;  // ой как некрасиво :-)
Т.е. кто угодно может иметь связи, нужно только в деструкторе вычеркнуть себя из хеша. Зато не морочить голову с навязчивым множ наследованием, подкладкой базового клааса и.т.п. Не, я конечно понимаю что так "низзя", но заманчиво... Улыбающийся

« Последнее редактирование: Январь 20, 2019, 13:56 от Igors » Записан
ssoft
Программист
*****
Offline Offline

Сообщений: 579


Просмотр профиля
« Ответ #58 : Январь 21, 2019, 09:33 »

Отношения между объектами  могут быть самыми разнообразными и выражаться самым разным ф-ционалом, как раз проблема в том что этих отношений очень много. Но с "владением" они никак не связаны - объект либо существует в сцене - либо нет, и значит он сам удален. Вот и все

Понятие отношений (ассоциаций) в объектно-ориентированном моделировании имеют четкие определения, в том числе и агрегация (https://www.uml-diagrams.org/aggregation.html?context=class-diagrams), как частный случай. Это отношение показывает кто-кого-когда-как удаляет. Требование к непротиворечивости модели определяет, могут ли определенные отношения сосуществовать вместе.

Для решения одной и той же задачи можно построить несколько непротиворечивых моделей отношений. Выбрать одну из них по каким-либо критериям - задача программиста. Именно поэтому возникает столько вопросов по нюансам каждой из задачи.

Тот же пример: отношение "иерархия" (парент-чайлд) визуализировано в виде дерева. Да, удаление/копирование парента применяется ко всем его чайлдам, но это же вовсе не значит что "парент владеет чайлдом" - просто он может (или имеет право) удалять/копировать объекты сцены.

Как легко Вы смешиваете несмешиваемое Веселый.

Визуализация в виде дерева не является каким либо отношением, это всего лишь удобное представление. Можно реализовать 100500 разных представлений для одной и той же модели данных. Представление является только отражением модели данных, даже если данные агрегировали внутрь конкретного представления. Данные первичны, представление вторично.

Да, удаление/копирование парента применяется ко всем его чайлдам, и в рамках понятий объектно ориентированной модели - это обязательно означает, что "парент владеет чайлдом".

В представленном конкретном случае, сами объекты сцены не участвуют ни в каких отношениях "парент-чайл", хотя Вы упорно пытаетесь их заставить  Веселый. В отношениях участвуют промежуточные данные, содержащие ассоциативные связи с этими объектами, а не сами объекты.

Вот есть 3D сцена в которую юзверь добавляет 3D объекты, напр модели, камеры, источники света и.т.п. Кто "владеет" этими объектами? Наверное академически правильно сказать: класс "сцена", но можно и по-простому: "контейнер объектов".
...
Как видите, вопрос "владения" для объектов верхнего уровня не стоит выеденного яйца. С ним давным-давно все ясно (объектами владеет сцена), и постоянно скатываясь во "владение" мы только толчем воду в ступе.

Случай, когда объектами владеет сцена, является частным (могут быт и другие решения). И конкретно в данном случае, действительно сцена является контейнером (агрегатором) объектов сцены. Именно через API класса сцены происходит добавление/удаление и т.п., другими словами - управление временем жизни объектов сцены. Сцена реально "владеет" своими объектами. Удаление объекта из сцены сделает все ссылки на него невалидными, поэтому требуется писать дополнительный по управлению этими ссылками (удаление из деревьев и т.п.). Напротив, удаление ссылки никаким образом не влияет на сам объект.

Дерево предполагает что нод имеет одного (и только одного) парента. Это так в подавляющем большинстве случаев, но все же не всегда. Пример: объекты типа Bone (кости, по-простому отрезок или точка) управляют полигонной моделью, как правило к модели линкуется 100 и более костей. Но никто не мешает прилинковать ту же кость(и) к др модели(ям). "Только один парент" здесь никак не выходит. Поэтому все-таки граф (не пойму чем это совершенно безобидное слово так ранит любителей std  Улыбающийся)

Если экземпляром объекта типа Bone "кость" владеет сцена, то помещайте в деревья экземпляры объектов типа LinkToBone, с линком к Bone. Не хотите, чтобы сцена владела "костями", помещайте в деревья экземпляры объектов типа SharedBone.

Поэтому все-таки граф (не пойму чем это совершенно безобидное слово так ранит любителей std  Улыбающийся)

Граф - это очень емкое понятие. Любые отношения образуют граф. Способов реализации - миллион. Оптимальной реализации на все случаи жизни - нет.
Частных случаев под определенный класс задач - масса. Наиболее известные простые - односвязный и двухсвязный список.
Более сложные из темы 3D - отношения между вершинами/ребрами/гранями/объемами. Различных реализаций тоже много.
Запихнуть все в единую реализацию графа - не очень здравая мысль. Как минимум, получится не оптимально.

Само понятие "дерева" следует реализовать в виде шаблона, узлы которого композитно агрегируют (уникально владеют) данными. Тип данных является параметром шаблона.
Понял так что, мол, template - это признак грамотности, давайте совать его везде. Но не вижу как (или чем) он здесь поможет.

 Смеющийся Грамотность тут ни при чем. Дерево, по своей сути, тоже является контейнером (агрегатором) общего назначения подобно ::std::list, ::std::map и др. Просто видов деревьев достаточно много, поэтому они не входят в std.
Вам нужна конкретная реализация дерева, но для разных случаев "by hierarchy", "by master material" и т.п. Поэтому template самое оно  Подмигивающий.

Любой из контейнеров можно легко реализовать без шаблонов, прямо на void*. Но чтобы так не делать, собственно, и разработали язык шаблонов.

Все 3D объекты унаследованы от базового класса, напрашивается добавить менеджер ссылок к нему. Но меня почему-то упорно тянет сделать этот менеджер внешним классом (хешем), напр
Код:
QHash<BaseClass *, CGraphNode> theReferenceHash;
Все-таки пробежка по всем ссылкам (хотя бы их дебаг печать и I/O) - ценная возможность, да и далеко не каждый объект имеет ссылки/связи. Или даже вот так, вызывающе
Код:
QHash<void *, CGraphNode> theReferenceHash;  // ой как некрасиво :-)
Т.е. кто угодно может иметь связи, нужно только в деструкторе вычеркнуть себя из хеша. Зато не морочить голову с навязчивым множ наследованием, подкладкой базового клааса и.т.п. Не, я конечно понимаю что так "низзя", но заманчиво... Улыбающийся

Так тоже будет работать), только медленнее. Если вдруг многопоточка - конкурентный доступ к theReferenceHash. Любой поиск связи - обращение к QHash. В 3D, где важны микросекунды - это может быть существенно.
Что будет в качестве ключа BaseClass *, void *, Handle не важно, если не используется reinterpret_cast или static_cast. Красиво/не красиво - дело вкуса. Главное, чтобы работало как нужно и удовлетворяло требованиям по производительности и др.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #59 : Январь 21, 2019, 11:50 »

Как легко Вы смешиваете несмешиваемое Веселый.
...
Можно реализовать 100500 разных представлений для одной и той же модели данных. Представление является только отражением модели данных, даже если данные агрегировали внутрь конкретного представления. Данные первичны, представление вторично.
Почему люди (даже хорошие) повторяют эту песню model-view хотя ее несуразность очевидна и лезет из всех щелей? Улыбающийся Ну спрятались за термин "представление", что это меняет? "Только отражение" возможно лишь в простейшем случае. Чтобы отобразить flat контейнер в виде дерева - уже нужно как минимум создать связи и где-то их хранить (хотя бы m_parent). Тогда в чем "вторичность представления" если оно рулит данными о которых оригинальная модель (flat контейнер) понятия не имеет? Эти данные чем-то неполноценны и отношением считаться не могут? Чем же?

Визуализация в виде дерева не является каким либо отношением, это всего лишь удобное представление.
...
В представленном конкретном случае, сами объекты сцены не участвуют ни в каких отношениях "парент-чайл", хотя Вы упорно пытаетесь их заставить  Веселый
...
Напротив, удаление ссылки никаким образом не влияет на сам объект.
То же отношение "иерархия" (если хотите "представление"). Линковка одного объекта к другому обычно выполняется с целью наследования трансформов парента (т.е. чайлд двигается (и/или врашается, скалится, деформируется и.т.п.) вместе с парентом, т.е. логика та же - операции над парентом применяются к его чайлдам. Если чайлд имеет свои анимации, то они должны быть пересчитаны так чтобы на момент линковки были дефаултами. Аналогично при отлинковке. Поэтому говорить о том что, мол, "никаких отношений между объектами нет" явно неуместно, да и просто противоречит здравому смыслу. Отношение "иерархия" налицо, подтверждается и визуально, и опциями, и как угодно. А что оно не вписывается в каноны model-view - так в этом я не виноват  Улыбающийся

В представленном конкретном случае, сами объекты сцены не участвуют ни в каких отношениях "парент-чайл",
...
В отношениях участвуют промежуточные данные, содержащие ассоциативные связи с этими объектами, а не сами объекты.
Из чего сие следует? Только из того что способ хранения объектов в сцене выбран flat? Стало быть, никаких "отношений" быть не может. Вот был бы способ хранения "дерево" - тогда было бы отношение "иерархия" (и только оно, а там только для UI надо пяток). Вам не кажется такой подход, мягко говоря,  "формальным"? Мы что, не можем наладить связи для организации любого числа структур? Какая разница где храним? Ну хорошо, пусть будут "представления" если религия не позволяет "отношения" Улыбающийся

Вам нужна конкретная реализация дерева, но для разных случаев "by hierarchy", "by master material" и т.п. Поэтому template самое оно  Подмигивающий.

Любой из контейнеров можно легко реализовать без шаблонов, прямо на void*. Но чтобы так не делать, собственно, и разработали язык шаблонов.
Ну давайте копнем какое там "оно" Улыбающийся  Вот набросок на базовом (god) классе Node
Код
C++ (Qt)
struct CGraphArc {
...
  TArcType mType;
  Node * mNode;
};
 
struct Node {
...
 QVector<CGraphArc> mInput, mOutput;  
};
Вполне норм, ну может базовый класс обременяется 2-мя контейнерам, но это уровне ощущений. Ваш вариант на template ? 
Записан
Страниц: 1 2 3 [4] 5 6   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.136 секунд. Запросов: 22.