2016-07-13 6 views
0

Я пытаюсь реализовать класс с пользовательским потоковым оператором и наследует его, чтобы иметь базовый класс и производный с разными потоками. Затем я перегружаю оператор << для использования сохраненных ostream.Пользовательский ostream печатает только последнюю строку `<<` chain

Это рабочий пример кода:

#include <string> 
#include <memory> 
#include <ostream> 
#include <iostream># 
#include <fstream> 

class Sink { 
public: 
    Sink() { 
     m_stream = std::unique_ptr<std::ostream>(new std::ostream(std::cout.rdbuf())); 
    }; 

    template<typename T> 
    std::ostream& operator<<(const T& obj) { 
     return *m_stream; 
    } 

protected: 

    std::unique_ptr<std::ostream> m_stream; 
}; 

class FileSink : public Sink { 
public: 

    FileSink() { 
     m_stream = std::unique_ptr<std::ostream>(new std::ofstream("file.txt")); 
    } 
}; 

int main() { 
    Sink s; 
    FileSink fs; 
    s << "First console string " << "second console string"; 
    fs << "First file string " << "second file string"; 
    return 0; 
} 

С Sink class я пишу на консоли, с FileSink на файл.

Проблема в том, что с этим кодом я печатаю только последнюю строку каждой инструкции.

В консоли я вижу следующий вывод:

second console string 

в то время как в файле я могу видеть этот вывод:

second file string 

Что я делаю неправильно и как я могу напечатать ожидаемый выход ?

+0

Хороший пример для злоупотребления std :: unique_ptr (простой указатель будет здесь) –

+0

@ DieterLücking Что такое преимущество raw pointer? – ilotXXI

+0

@ DieterLücking, если класс Sink владеет указателем, почему бы не использовать unique_ptr? В противном случае вам понадобится индивидуальная копия или перемещение конструктора, а деструктор –

ответ

3

Ваш operator<< ничего не делает и возвращает std::ostream&. Затем вы применяете std::ostream::operator<< к этому std::ostream&. Ожидаемая вещь!

Стандартный способ сделать то, что вы хотите:

template<typename T> 
Sink & Sink::operator<<(const T& obj) { 
    *m_stream << obj; 
    return *this; 
} 
template<typename T> 
FileSink & FileSink::operator<<(const T& obj) { 
    *m_stream << obj; 
    return *this; 
} 

Чтобы избежать дублирования кода можно использовать наследование. Я думаю, он может дублировать схему наследования std::stream. :)

2
template<typename T> 
std::ostream& operator<<(const T& obj) { 
    *m_stream << obj; // you missed this 
    return *m_stream; 
} 

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

template <typename T> 
Sink& operator<<(Sink &sink, const T &obj) { 
    *(sink.m_stream) << obj; 
    return sink; 
} 

и сделать его друга Раковина:

class Sink { 
    template <typename T> 
    friend Sink& operator<<(Sink &sink, const T &obj); 
    // other code. 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^