Как я могу сократить одноэлементный вызов?

#c

#c

Вопрос:

У меня есть одноэлементный класс, который в основном имеет дело с журналами. В каждом месте кода, в котором я его вызываю, я должен вводить:

 LogClass::GetInstance()->WriteToLog("text");
  

Как я могу сократить этот вызов, чтобы я мог просто ввести WriteToLog("text") , и он вызовет функцию для одноэлементного объекта?

Комментарии:

1. Не использовать синглтоны?

2. @DeadMG проходил через это раньше. Некоторым людям не нравятся синглтоны, но никто не смог привести вескую причину, почему нет.

3. Есть ли что-нибудь, что мешает вам сделать очевидную вещь — написать бесплатную функцию с именем, WriteToLog которая просто оборачивает GetInstance() / WriteToLog() функциональность?

4. @James: Я думаю, что общая идея заключается в принципе, что вы не позволяете себе использовать несколько инкапсулированных объектов одного заданного типа, но вы используете объекты, и поэтому вы можете использовать объекты без причины (и, таким образом, попадаете в ловушку «всегда используйте объект», что является мифом). Конечно, на практике это происходит довольно быстро, поскольку контроль, который вы получаете над созданием экземпляра, часто неоценим.

5. @James: Мне не нравятся синглтоны, потому что (а) они включают глобально доступный объект, и мне нравятся структурированные проекты; (б) они встраивают механику управления объектами в сам класс, и мне нравится гибкость отделения управления объектами от реализации; (с) в C их трудно реализовать безопасно.

Ответ №1:

Используйте функцию пересылки

 inline void WriteToLog(...string...)
{ LogClass::GetInstance()->WriteToLog(.....string......); }
  

Комментарии:

1. и вставить куда? в LogClass ? или в каком-то глобальном файле include h?

2. Вне класса или где-то еще, где это необходимо.

3. Поместите приведенный выше код в файл C , где вы реализуете LogClass , и поместите прототип этой функции в нижней части файла заголовка, где вы объявляете LogClass .

4. зачем мне нужен prototype внизу? можете ли вы привести пример?

5. @user63898 — Вам не нужен отдельный прототип, если вы добавите туда встроенную функцию. Встроенные функции гораздо предпочтительнее макросов. 🙂

Ответ №2:

Добавьте статическую функцию в LogClass:

 class LogClass {

    static void Write( const std::string amp; s ) {
         GetInstannce()->WriteToLog( s );
     }
};
  

затем:

 LogClass::Write( "foobar" );
  

Комментарии:

1. могу ли я как-то отклонить LogClass? и иметь возможность писать только Write () в каждом месте?

2. @user Сделай то, что предлагают другие, и напиши свободную функцию. Но мне больше нравится статический вариант — так понятнее, что происходит.

Ответ №3:

 #define LOG(str) LogClass::GetInstance()->WriteToLog(str);
  

Ответ №4:

Вы можете использовать указатель для временного хранения псевдонима класса локально в вашей функции: (При условии, что «getInstance возвращает указатель на одноэлементный)

  void foo()
 {
    Singleton* logger = LogClass::GetInstance();
    logger->WriteToLog(...string...);
    logger->WriteToLog(...string...);
 }
  

Ответ №5:

Мне нравится использовать ссылку и перегрузку operator().

В файле LogClass.h

 class LogClass
{
    public:

        static LogClassamp; GetInstance()
        {
            static LogClass singleton;
            return singleton;
        }

        void operator()( std::string msg );

        //...
};


extern LogClassamp; myDebug;
  

В LogClass.cpp файл

 LogClassamp; myDebug = LogClass::GetInstance();

void LogClass::operator()( std::string msg )
{
    // my stuff to to with the msg...
}

//...
  

Тогда я могу использовать его таким образом (в любой файл LogClass.h включен):

 myDebug("text");
  

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


Далее я хотел бы добавить простой переключатель для одновременного отключения всех debugMsg…

итак, я добавляю следующее:

 #if DEBUG_MODE
    #define MY_DEBUG( msg ) myDebug( msg )
#else
    #define MY_DEBUG( msg ) // will replace the myDebug calls by nothing.
#endif
  

Таким образом, я могу использовать:

 MY_DEBUG("text");  // instead of myDebug("text");
  

Таким образом, я могу легко отключить все сообщения отладки сразу.

Комментарии:

1. отличная идея, она мне понравилась, но почему бы не использовать МАКРОС, как предложил Томалак Герет’кал?

2. На самом деле есть две причины: Во-первых, это был выбор дизайна, чтобы сделать его пригодным для использования точно так же, как std:: cout или std:: cerr (мой класс printDebug наследует std:: ostream, поэтому его можно использовать как std :: cout с манипуляторами и т.д. … И я передаю каналы / детализацию в скобках). Таким образом, я могу myDebug(V_CRITICAL, {1,2,3}) << "val:" << myVal << std::endl; отправить критическое сообщение отладки по каналам 1,2 и 3. (Но это также можно сделать с помощью макроса …)

3. Далее, вторая причина заключается в целях оптимизации; поскольку я использую его для очень интенсивного вывода отладки (тысячи отладочных сообщений в секунду) Я решил вызвать метод getInstance один раз вместо того, чтобы вызывать его каждый раз, когда я хочу отправить новое сообщение.

4. В завершение, я думаю, что МАКРОС, подобный предложенному Томалаком Герет’Калом, лучше, чем мое решение. Но я должен был предложить идею (идеи дают идеи), и это решение, если мы хотим избежать рекурсивного вызова getInstance.

Ответ №6:

Лично я считаю плохой практикой выставлять «синглтон».

Раньше у меня были static функции над static состоянием:

 class Logger {
public:
  static void Write(std::string constamp; s);
private:
  static std::ifstream _file;
};
  

Однако сейчас я предпочитаю использовать моноиды. Конечно, это всего лишь замаскированные синглтоны, но впоследствии гораздо проще отказаться от одноэлементности.

 class Logger {
public:
  void Write(std::string constamp; s);
private:
  static std::ifstream _file;
};
  

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