2016-07-13 17 views
0

Ich versuche, eine Klasse mit einem benutzerdefinierten Stream-Operator zu implementieren, und erbt von ihm, um eine Basisklasse und eine abgeleitete mit verschiedenen Streams zu haben. Dann überlade ich den Operator << für die Verwendung von gespeicherten ostream.Benutzerdefiniertes Ostream druckt nur die letzte Kette von `<<` Kette

Dies ist eine Arbeitsprobe des Codes:

#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; 
} 

Mit dem Sink class ich auf der Konsole zu schreiben, mit FileSink auf eine Datei.

Das Problem ist, dass ich mit diesem Code nur letzte Zeichenfolge jeder Anweisung drucken.

in der Konsolen ich folgende Ausgabe:

second console string 

während in der Datei kann ich diese Ausgabe sehen:

second file string 

Was mache ich falsch und wie kann ich die erwartete Ausgabe drucken ?

+0

Ein gutes Beispiel für den Missbrauch von std :: unique_ptr (ein einfacher Zeiger wäre genau hier) –

+0

@ DieterLücking Was ist ein roher Zeiger Vorteil? – ilotXXI

+0

@ DieterLücking Wenn Sink-Klasse den Zeiger besitzt, warum nicht ein unique_ptr verwenden? Andernfalls benötigen Sie eine angepasste Kopie oder einen Move-Konstruktor und einen Destruktor –

Antwort

3

Ihre operator<< tut nichts und gibt std::ostream&. Dann wenden Sie std::ostream::operator<< zu diesem std::ostream& an. Erwartete Sache!

Standard-Art zu tun, was Sie wollen:

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; 
} 

Um Code-Duplizierung zu verhindern Sie die Vererbung verwenden können. Es könnte Duplikat std::stream Vererbungsschema, denke ich. :)

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

Sie können aber auch Betreiber < < als Nicht-Mitglied-Funktion definieren.

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

und es einen Freund von Wasch- oder Spülbecken machen:

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