#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;
};
Вам все еще приходится решать все проблемы с одиночными элементами, но вы можете с большей легкостью отказаться от этого.