Перегрузка оператора ostream ‹‹ для статического класса?

У меня есть (упрощенный) статический глобальный класс и перегрузка оператора ‹‹ следующим образом:

class Global
{
    private:
    static int counter;
    Global(){};

    public:
    friend ostream& operator<<(ostream &out, Global &global);
}

ostream& operator<< (ostream &out, Global &global)
{
    //... do output
    return out;
}

Я хочу иметь возможность передавать статическую ссылку на cout:

cout << Global

Однако оператору ‹‹ нужен экземпляр, хотя на самом деле экземпляров этого глобального класса не существует. Есть ли что-нибудь вокруг этого?

Спасибо за любую помощь.


person jamieQ    schedule 10.11.2009    source источник


Ответы (3)


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

В общем, если вы хотите ввести «потоковое» имя без определения объекта, вы должны написать манипулятор потока:

std::ostream& foo(std::ostream& out)
{
    out << "foo";
    return out;
}

Хитрость здесь в том, что потоки имеют перегруженный оператор <<, так что если вы передаете ему указатель на функцию, и эта функция принимает и возвращает поток, то << будет эквивалентно применению функции к потоку. Другими словами, вы можете написать:

std::cout << 123 << foo << 456;

и это будет так же, как:

foo(std::cout << 123) << 456;

Например, так реализовано std::endl.

То же самое относится и к >>, и вы можете предоставить функцию шаблона для basic_istream и/или basic_ostream, если хотите, чтобы она была более общей.

person Pavel Minaev    schedule 11.11.2009
comment
Спасибо, это то, что нужно :) - person jamieQ; 11.11.2009

шаблон Singleton.

Вот один из способов реализации шаблона с учетом вашего примера (не проверено на ошибку):

class Global
{
   private:
   static int counter;
   Global(){};
   static Global *_instance;

   public:
   static Global getInstance() { 
     if (!_instance) 
        _instance = new Global();
     return *_instance; 
   }
   friend ostream& operator<<(ostream &out, Global &global);
}

Global* Global::_instance = NULL;

ostream& operator<< (ostream &out, Global &global)
{
    //... do output
    return out;
}

Тогда ваш код вызова будет выглядеть так:

cout << Global::getInstance()
person Cogwheel    schedule 10.11.2009
comment
Шаблон Singleton, вероятно, лучшая идея. Так или иначе, вам понадобится экземпляр Global. - person Charles Salvia; 11.11.2009
comment
Конечно, вы всегда можете сделать конструктор общедоступным и просто выполнить std::cout << Global(); но вам может показаться неприятным разрешить здесь публичный конструктор. - person Charles Salvia; 11.11.2009
comment
Это утечка ресурсов. Используйте синглтон Мейера для простого решения. Если вы хотите использовать динамическое размещение, вам нужно добавить хуки на выходе. - person GManNickG; 11.11.2009
comment
Отсюда один способ, которым вы можете это реализовать ;) Для такого тривиального примера, разве это не проблема? Время жизни статического объекта — это все время выполнения программы. Память будет освобождена ОС при выходе, не так ли? - person Cogwheel; 11.11.2009
comment
Согласен, это всего лишь утечка по определению, о чем мои инструменты обнаружения утечек сообщают как об утечке. Тем не менее, чистый лист инструментов для обнаружения утечек необходим, если вы собираетесь их часто использовать. Это тот же принцип, который гласит, что вы исправляете предупреждения, даже если они являются ложными срабатываниями. - person Steve Jessop; 11.11.2009
comment
Очередной раз. Почему o Почему вы используете указатель для вашего синглтона. Прочитайте это: stackoverflow.com/questions/1008019/c -singleton-design-pattern/ - person Martin York; 11.11.2009
comment
@Cogwheel: Утечка вряд ли когда-либо является проблемой с памятью, проблема заключается в том, что вы не убираете ресурсы. Память — это всего лишь упрощенный ресурс, и поэтому его легко объяснить в CS101. Когда у вас есть настоящие программы с деструкторами, утечка ресурсов является проблемой, а доказательство правильности программы при утечке ресурсов становится настоящей проблемой. - person Martin York; 11.11.2009

Если вы действительно хотите вызвать такую ​​функцию без экземпляра объекта, вы можете сделать это следующим образом:

std::cout << *(Global*)NULL;

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

person Tim Sylvester    schedule 10.11.2009
comment
Но если вы это сделаете, просто убедитесь, что ваша перегрузка ostream обращается к членам статически, например Global::counter, а не через нулевую ссылку. - person Charles Salvia; 11.11.2009