2016-07-13 1 views
0

J'essaie d'implémenter une classe avec un opérateur de flux personnalisé, et en hérite pour avoir une classe de base et une dérivée avec des flux différents. Ensuite, je surcharger l'opérateur << pour utiliser ostream stocké.Ostream personnalisé imprime seulement la dernière chaîne de `` `chaîne

Ceci est un exemple de travail du code:

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

Avec le Sink class j'écris sur la console, avec FileSink sur un fichier.

Le problème est qu'avec ce code j'imprime seulement la dernière chaîne de chaque instruction.

Dans la console, je vois sortie suivante:

second console string 

alors que dans le fichier que je peux voir cette sortie:

second file string 

Ce que je fais mal et comment puis-je imprimer la sortie attendue ?

+0

Un bon exemple pour abuser de std :: unique_ptr (un pointeur simple serait juste ici) –

+0

@ DieterLücking Qu'est-ce qu'un avantage de pointeur brut? – ilotXXI

+0

@ DieterLücking si la classe Sink possède le pointeur, pourquoi ne pas utiliser un unique_ptr? Sinon, vous avez besoin d'une copie personnalisée ou d'un constructeur de déplacement, et d'un destructeur –

Répondre

3

Votre operator<< ne fait rien et renvoie std::ostream&. Ensuite, vous appliquez std::ostream::operator<< à ce std::ostream&. Chose attendue!

méthode standard pour faire ce que vous voulez:

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

Pour éviter les doubles emplois, vous pouvez utiliser l'héritage de code. Il peut reproduire le schéma d'héritage std::stream, je pense. :)

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

Vous pouvez également définir l'opérateur < < en fonction non-membre.

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

et en faire un ami de Sink:

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