Альтернативы статическому и глобальному в С++?

У меня есть экземпляр класса, к которому должны обращаться некоторые другие классы.

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

error: calling a private constructor of class 'Foo'

Чтобы уточнить проблему в контексте QGraphicsView Framework: Я хочу добавить QGraphicsItems, которые создаются классом контроллера (управление элементами) в QGraphicsScene, который (но я не настаиваю на этой детализации) является членом моего класса QMainWindow.

Я трачу немало времени на поиск в Интернете, но я довольно новичок и здесь застрял. Я ценю любые стимулы к тому, что лучший способ решить эту дилемму будет.

Ответ 1

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

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

  • Когда я создаю библиотеку, я стараюсь избегать глобальных объектов, кроме одного factory. Глобальные объекты часто используются в качестве ярлыка, где не требуется ярлык или чтобы избежать ввода текста для программиста. Кроме того, в основном классы в библиотеке должны быть независимыми. Вы жертвуете независимостью, если вы используете глобальные экземпляры внутри таких классов.

  • Когда я использую статику в классе, я использую их только в том случае, если весь класс является одноточечным или для методов factory (например, создавать или получать). Никогда так, как вы описали. В том, как вы его описали, это неожиданно для другого разработчика, потому что для инициализации этого статического объекта требуется сторонняя сторона. Вы ничего не получаете с этим, кроме как избежать ввода более длинного конструктора. Это не может быть целью.

  • Если я использую глобальный экземпляр, я всегда переношу его в класс управления. Я никогда не использую сторонние классы, такие как QGraphicsItems direct, как глобальные (также нет "примитивных" классов или типов). Как и в пункте 2, другие не могут ожидать этого как глобального. Более важно неясно, кто должен заполнить или убить экземпляр. "GraphicsItemManager" может иметь метод "настройки", который делает это полностью понятным для третьих пользователей.

  • Передача экземпляров не в каждой ситуации лучшим способом ИМХО. Не все мои классы предназначены для повторного использования, они предназначены исключительно для одного проекта. Здесь скорость реализации, простота использования и четкая группировка стоят больше, чем догма как "без глобалов". В большинстве случаев я пишу классы менеджеров, которые группируют экземпляры, например. графические элементы. У меня нет чувства, что код становится менее читаемым, поскольку я использовал ранее описанные правила.

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

Как я написал ИМХО.

Ответ 2

Эта проблема возникает, когда у вас есть проект, в котором класс A создает класс B, который создает класс C, который должен принять экземпляр класса D в своем конструкторе. Затем вы должны пройти D полностью через A, B и C. Если вы измените дизайн на наличие функции экземпляра create (либо в основном, либо в классе factory), который знает, как создать A, B, C и D. Затем вы можете записать эту функцию следующим образом:

D d;
C c(d);
B b(c);
A a(b);

Таким образом, каждый класс принимает только свои зависимости.

Если вы позже поймете, что B также нужно использовать класс D, тогда вы можете просто сменить конструктор B, не затрагивая конструктор A.