User 13204940 Ответов: 1

Работа с циклическими зависимостями, когда они вам нужны


Привет,

Вы уже знаете, с чем я имею дело, прочитав название этого вопроса, и это не весело.

У меня есть около 20 классов, где некоторые относятся к другим, которые относятся обратно. Например,
AEntity* InventoryItem::ToEntity();
InventoryItem* AEntity::ToItem();


Я обнаружил, что, комментируя весь код в cpp одного файла в цикле и комментируя его включение в файл .h, ошибки исчезают. Я получаю около 90 нерелевантных ошибок из-за этой проблемы. Я не буду перечислять их здесь, но это такие вещи, как:

• xxx не является членом 'yyy'
• отсутствует спецификатор типа - предполагается int (где у меня есть тип явно там)
• синтаксическая ошибка: отсутствует ';' перед '*' - щелчок по ошибке показывает совершенно прекрасный код, спасибо intellisense
• ожидаемый токен(ы), предшествующий ';'

Я даже попытался переместить один из включений в цикле в cpp этого файла вместо .h, И это работает. С другими это не так, и эти ошибки все еще существуют. Кроме того, я презираю идею иметь некоторые включения в .h и некоторые в .cpp, это грязно.

Как лучше всего с этим справиться?

Что я уже пробовал:

Все уже упомянутое под вопросом.

0x01AA

Циклическая зависимость:
Когда это вообще возможно, избегайте этого, Но да, я знаю ситуацию.

Одним из решений было бы использование только динамических экземпляров. Это позволит вам "переадресовать объявление" указателя в клиенте .h и избавит от необходимости включать a .h в вашем .h

Richard MacCutchan

У вас не возникает ощущения, что ваш код становится слишком похожим на тарелку спагетти? Откровенно говоря, глядя на две строчки выше, я начинаю косить глазами.

Patrice T

Я подозреваю, что это большая проблема дизайна, но не видя ваших классов, как сказать ?

[no name]

Идея состоит в том, чтобы иметь сущность в мире, которую вы можете взять, и это становится предметом в вашем инвентаре, и вы можете поместить его снова, чтобы произвести сущность.

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

Если нет никакого осуществимого способа сделать это, мне, возможно, придется просто иметь класс entity с переменными, такими как isSpawned() и все vars и методы как для элемента, так и для сущности, которые используются в зависимости от контекста

1 Ответов

Рейтинг:
0

KarstenK

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

Распространенными обходными путями являются прямые объявления или интерфейсы. Вы также можете использовать указатели void в качестве аргументов функции и затем привести их в реализацию. Или в зависимости от операционной системы, работающей с сообщениями или обратными вызовами. Я использовал некоторые "плоские интерфейсы", в которых все аргументы сложного объекта передаются как простые данные.

Лучше всего взять пустой лист бумаги, чашку любимого напитка и закуску и начать с нуля.


0x01AA

+5