Переопределение оператора << в синглтоне - PullRequest
0 голосов
/ 10 ноября 2011

У меня есть класс на C ++ в Linux, который позволяет мне отображать сообщения на консоли в зависимости от того, где запущено приложение. Если это работает на моем компьютере, сообщения отображаются в режиме консоли. В противном случае все записывается в текстовом файле для последующего просмотра. И я создал внешний объект, чтобы использовать его. Я хотел попытаться сделать этот класс одиночным, но безуспешно. У меня эта ошибка появляется, когда я прихожу, чтобы скомпилировать мою программу:

ошибка: недопустимые операнды типов 'Log *' и 'const char [12]' в двоичный оператор '<<' </p>

А также:

ошибка: нет совпадения для 'operator <<' в 'logOutput' << Buffer_T .... </p>

Мне бы хотелось ваше мнение. Заранее благодарю за внимание.

Мой функциональный класс в настоящее время

typedef std::vector<unsigned char> Buffer_T;

class Log
{
public:
    Log();
    virtual ~Log();

    void init()
    {
    #indef FriendlyArm
        output = new ofstream("/home/arm/Log.txt");
    #else
        output = &cout;
    #endif
    }


    template<typename T>
    Log operator<<( T const& value )
    {
        (*output) << value;
        return *this;
    }

    Log& operator<<( std::ostream&(*f)(std::ostream&) )
    {
        (*output) << f;
        return *this;
    }

    Log& operator<<(Buffer_T& Buf)
    {
        if( Buf.size() > 0 )
        {
            for( unsigned int i = 0; i < Buf.size(); i++ )
            {
                if( Buf[i] >= 32 && Buf[i] <= 127 )
                {
                    (*output) << Buf[i];
                }
                else
                {
                    (*output) << "0x" << std::setfill( '0' ) << std::hex << std::setw( 2 ) << unsigned( Buf[i] );
                }
            }
        }
        return *this;
    }


private:
    ostream *output;
};
#endif /* LOG_H_ */

А вот и моя попытка синглтона

typedef std::vector<unsigned char> Buffer_T;

class Log
{
    public:
        static Log *createOrGet()
        {
            if(_unique == NULL)
            {
                _unique = new Log();
            }

            return _unique;
        }

        static void kill()
        {
            if(_unique != NULL)
            {
                delete _unique;
                _unique = NULL;
            }
        }

        void init()
        {
        #indef FriendlyArm
            output = new ofstream("/home/arm/Log.txt");
        #else
            output = &cout;
        #endif
        }

        template<typename T>
        Log operator<<( T const& value )
        {
            (*output) << value;
            return *this;
        }

        Log& operator<<( std::ostream&(*f)(std::ostream&) )
        {
            (*output) << f;
            return *this;
        }

        Log& operator<<(Buffer_T& Buf)
        {
            if( Buf.size() > 0 )
            {
                for( unsigned int i = 0; i < Buf.size(); i++ )
                {
                    if( Buf[i] >= 32 && Buf[i] <= 127 )
                    {
                         (*output) << Buf[i];
                    }
                    else
                    {
                        (*output) << "0x" << std::setfill( '0' ) << std::hex << std::setw( 2 ) << unsigned( Buf[i] );
                    }
                }
            }
            return *this;
        }

    private:
        Log();
        virtual ~Log();
        static Log *_unique;
        ostream *output;
};
Log *Log::_unique = NULL;
#endif

Ответы [ 3 ]

1 голос
/ 10 ноября 2011

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

У меня нет времени, чтобы разобраться, почему operator<< не работает для вас, новот несколько советов о том, как улучшить ваш синглтон (вы также, кажется, просите совета по этому поводу).

Функция экземпляра

// The idiomatic way is to call this function 'Instance',
// but this doesn't really matter.
static Log& Instance() {
    static Log obj;
    return obj;
}

Это называется синглтоном Мейера,Для однопоточного приложения это здорово: экземпляр создается при первом вызове функции, а автоматически уничтожается при закрытии приложения (вам не нужна функция kill).

Ваш личный виртуальный деструктор

Я заметил, что у вас есть личный виртуальный деструктор.Вам нужен только виртуальный деструктор, когда в классе есть хотя бы одна другая виртуальная функция.Это не вариант;сделать деструктор не виртуальным.

принудительное использование одного экземпляра

Вы сделали конструктор частным - это хорошо, вы не позволяете мне напрямую создавать несколько экземпляров одиночного файла,Однако вы не помешали мне сделать копии существующего синглтона.Чтобы также предотвратить это, вам также нужно сделать CopyConstructor и AssignmentOperator закрытыми:

protected:
  Log();
  Log(const Log&); // CopyConstructor
  Log& operator=(const Log&); // AssignmentOperator
  ~Log();

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

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

0 голосов
/ 10 ноября 2011

В комментариях к вашему OP вы опубликовали следующий тестовый комплект:

int main()
{
    Log *logOutput; 
    logOutput = Log::createOrGet(); 
    logOutput << "ProcessCommand called";
    logOutput << Data << endl; // I dont know what Data is, so I commented this out
}

Вам необходимо разыменовать logOutput, чтобы перейти к нему.В противном случае вы используете потоковый указатель на журнал, а не на сам журнал.

Но у вас есть и другие проблемы.Шаблон вашего метода:

template<typename T>
Log operator<<( T const& value )
{
    (*output) << value;
    return *this;
}

возвращает значение Log по значению, что приводит к временному уничтожению, когда оно выходит из области видимости, но Log::~Log объявляется private, поэтому недоступно,

Измените operator<< s, чтобы получить Log по ссылке:

template<typename T>
const Log& operator<<( T const& value ) const
{
    (*output) << value;
    return *this;
}

Log& operator<<( std::ostream&(*f)(std::ostream&) )
{
    (*output) << f;
    return *this;
}

Log& operator<<(Buffer_T& Buf) 
{
    if( Buf.size() > 0 )
    {
        for( unsigned int i = 0; i < Buf.size(); i++ )
        {
            if( Buf[i] >= 32 && Buf[i] <= 127 )
            {
                    (*output) << Buf[i];
            }
            else
            {
                (*output) << "0x" << std::setfill( '0' ) << std::hex << std::setw( 2 ) << unsigned( Buf[i] );
            }
        }
    }
    return *this;
}
0 голосов
/ 10 ноября 2011

Из вашего комментария:

  Log *logOutput;
  logOutput = Log::createOrGet();
  logOutput << "ProcessCommand called" << endl;
  logOutput << Data << endl;

Проблема: Ваш Log::createOrGet() возвращает Log*, в то время как определенный operator<< принимает Log (обратите внимание на отсутствие *) там.

Есть два решения:

  • Используйте *logOutput везде. Это громоздко, поэтому лучше использовать альтернативу:
  • Измените определение на Log& logOutput; и настройте Log::createOrGet(), чтобы получить Log& (последний пункт: см. Определение Пола Манты для Instance())

Не забудьте также прочитать и понять замечания Пола Манты!

ПРИМЕЧАНИЕ : Хотя это решит указанное в сообщении об ошибке, это не решит другие проблемы в вашем коде. Переписывание вашего кода кажется единственным решением; см. ответ Пола Манты (снова) для предложений.

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