Это плохая практика для использования взаимозависимых классов? - PullRequest
2 голосов
/ 04 ноября 2010

Если у меня есть класс Container, который содержит кучу объектов Component (аналогично структуре пользовательского интерфейса Java), будет ли плохой стиль / практика отслеживать родительский элемент Container в каждом Component?

Это приводит к некоторым странным проблемам с компилятором, поскольку Component включает заголовочный файл для Container и наоборот.Даже с исправлением защиты заголовка мне приходится объявлять прототип class Component; поверх заголовка Container, и аналогично для Component.

Кажется, что вы должны пройти довольнонемного проблем, чтобы получить двустороннее взаимодействие между двумя классами.Было бы целесообразно найти другое решение проблемы, которую "решает" совместная зависимость, или эта запутанная реализация ожидается от C ++, и я должен просто смириться с этим?некоторый контекст / рассуждение помогло бы.Причина, по которой я использую эту взаимозависимость, заключается в том, что мне нужно уведомить родителя, когда вызывается деструктор ребенка (чтобы его можно было удалить из списка детей), и мне также нужно иметь нарисованную позицию ребенкабыть относительно того из родителей.

Спасибо,
Jengerer

Ответы [ 3 ]

2 голосов
/ 04 ноября 2010

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

2 голосов
/ 04 ноября 2010

Широко используется указатель на свой родительский компонент, и я не считаю это плохой практикой. Его можно использовать для самых разных целей, от обработки деревьев виджетов до обработки потерянных или утечек компонентов.

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

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

Widget.hpp:

#include "Library.hpp"

namespace MyLibrary
{
    class Widget
    {
    private:
        Window * parent;
    };
}

Window.hpp:

#include "Library.hpp"

namespace MyLibrary
{
    class Window
    {
    private:
        std::vector<Widget*> widgets;
    };
}

Library.hpp:

namespace MyLibrary
{
    class Window;
    class Widget;
}
2 голосов
/ 04 ноября 2010

Обычно лучше не иметь таких циклических зависимостей: они немного болезненны для кода, расстраивают логические рассуждения о коде, тестируемость и т. Д.

Их можно легко избежать в любом случае - вы могли бысохраните некоторые функторы в Компонентах, затем укажите их на операции Контейнера, соответствующие обрабатываемым событиям, или извлеките Контейнер из абстрактного интерфейса, чтобы у Компонентов мог быть указатель на него, и Контейнер выводил из него.Или Компоненты могут быть сохранены (умным) указателем, с производным типом, реализующим виртуальные обработчики событий, настроенные для контейнера.Существует множество других возможностей, например, если вы хотите избежать накладных расходов во время выполнения, рассмотрите классы политик CRTP или шаблонов.

...