Подтвердить что ты не робот

Какой правильный способ "С++" для выполнения глобальных переменных?

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

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

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

4b9b3361

Ответ 1

Используйте шаблон дизайна singleton.

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

См. ссылку о том, как использовать одноэлемент, а также эту ссылку fooobar.com/questions/633/...

Предупреждение. Шаблон одноэлементности предполагает продвижение глобального состояния. Глобальное состояние плохо по многим причинам.
Например: модульное тестирование.

Ответ 2

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

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

Ответ 3

Почему бы не использовать систему, которая уже установлена? То есть перенаправление 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;

Ответ 4

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

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

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

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

тогда вы тратите усилия.

Ответ 5

Журналы попадают под сферу "разделения беспокойства", как в аспектное ориентирование

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

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

Ответ 6

Я думаю, Service Locator будет делать. То, что вам придется либо обойти конструкторы, либо получить глобально доступную статическую функцию-член в каком-то известном месте. Первый вариант намного предпочтительнее.

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

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

Ответ 10

Просто передайте свой основной класс в конструктор других классов, к которому вы хотите иметь доступ ко всем "<" >

Затем вы можете предоставить доступ к журналу и т.д. через свойства участника. (Простите мой синтаксис С++, это всего лишь подготовленный язык под названием "С++, смущенный VB" )

например.

Class App {
     Private  m_logger;
     Private  m_config;

     Public logger() {
        return m_logger;
     }

     Public config() {
        return m_config
     }
}

Class Window1 {
     New( anApp ) {
     }
     ....
}

Ответ 11

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