Какой правильный "C ++ способ" сделать глобальные переменные? - PullRequest
12 голосов
/ 21 апреля 2009

У меня есть основной класс приложения, который содержит регистратор, а также некоторые общие настройки приложения и т. Д.

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

Я видел несколько вариантов, таких как объявление основного класса extern везде, но это не очень объектно-ориентировано. Каков «стандартный» C ++ способ сделать элементы основного класса доступными для всех (или большинства) других классов?

Ответы [ 11 ]

12 голосов
/ 21 апреля 2009

Используйте дизайн одноточечно рисунок .

В основном вы возвращаетесь статический экземпляр объекта и использовать его для всех ваших работ.

Пожалуйста, ознакомьтесь ссылку о том, как использовать синглтон , а также это StackOverflow ссылку о том, когда вы не должны использовать его

Внимание: синглтон шаблон включает в себя продвижение глобального состояния. Глобальное состояние плохо по многим причинам.
Например: модульное тестирование

.
7 голосов
/ 21 апреля 2009

Неплохая идея передать регистратор и конфигурацию всем конструкторам, если ваш регистратор и конфигурация достаточно абстрактны

Синглтон может стать проблемой в будущем. Но это кажется правильным выбором в начале проекта. Твой выбор. Если ваш проект достаточно мал - выбирайте синглтон. Если нет - внедрение зависимости.

6 голосов
/ 21 апреля 2009

Почему бы не использовать систему, которая уже установлена? То есть перенаправить std :: clog для вывода в файл и записи в std :: clog.

std::fstream *f = new std::fstream("./my_logfile.log")

std::clog.rdbuf(f->rdbuf());

std::clog << "Line of log information" << std::endl;
3 голосов
/ 21 апреля 2009

Я бы согласился с каким-то одноэлементным подходом. Вы определенно не хотите передавать объекты регистратора повсюду. Это станет очень скучным очень быстро, и ИМХО - худший дизайн, чем просто наличие простого глобального объекта.

Хорошим тестом на то, что у вас есть хорошее решение, являются шаги, необходимые для того, чтобы регистрация работала в функции, которая в этом нуждается.

Если вам нужно сделать гораздо больше, чем

#include "Logger.h"
...
void SomeFunction()
{
    ...
    LOGERROR << "SomeFunction is broken";   
    ...
}
...

тогда ты зря тратишь усилия.

2 голосов
/ 25 апреля 2009

Ведение журнала относится к сфере «разделения интересов», как в аспектно-ориентированном программировании

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

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

0 голосов
/ 24 июня 2009

Почему никто не подумал о наследии и полиморфизме? Вы также можете использовать абстрактную фабрику с этим синглтоном;)

0 голосов
/ 11 июня 2009

Просто передайте ваш основной класс в конструктор других классов, которым вы хотите иметь доступ ко «всему»

Затем вы можете предоставить доступ к регистратору и т. Д. Через свойства участника. (Простите мой синтаксис C ++, это всего лишь выдуманный язык под названием «C ++, сбитый с толку VB»)

, например

Class App {
     Private  m_logger;
     Private  m_config;

     Public logger() {
        return m_logger;
     }

     Public config() {
        return m_config
     }
}

Class Window1 {
     New( anApp ) {
     }
     ....
}
0 голосов
/ 21 апреля 2009

Почему бы не использовать log4cxx ? Такие проблемы давно решены и широко используются многими. Если вы не создаете какую-то совершенно особую систему ведения журналов самостоятельно ... В таком случае, я бы использовал шаблон Factory, который бы создавал регистраторы для всех, кто заинтересован (или отдавал существующий экземпляр, если он одиночный). Другие классы будут использовать фабрику для получения регистратора. Передача логгеров в параметрах конструктора - плохая идея, потому что она связывает ваш класс с логгером.

0 голосов
/ 21 апреля 2009

Я бы избегал одноэлементного паттерна.
Слишком много проблем, когда дело доходит до тестирования и тому подобное (см. Что плохого в синглетах? )

Лично я бы передал регистратор и т. Д. В конструктор. В качестве альтернативы вы можете использовать фабрику для создания / передачи ссылки на ресурс.

0 голосов
/ 21 апреля 2009

Не знаю, полезно ли это в вашей ситуации или нет, но в MFC был / есть класс приложения.

Я использую, чтобы бросать подобные вещи в этот класс.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...