2016-08-05 29 views
1

Ich möchte eine Variable vom Typ istream haben, die entweder den Inhalt einer Datei oder einen String enthalten kann. Die Idee ist, dass, wenn keine Datei angegeben wurde, die Variable vom Typ istream mit einer Zeichenfolge zugewiesen würde.Wie kann ich istringstream und ifstream einer istream-Variablen zuweisen?

std::ifstream file(this->_path) 

und

std::istringstream iss(stringSomething); 

zu

std::istream is 

Ich habe versucht, die Zuordnung nur um sie zu den istream Variable wie ich mit anderen Objekten würde, die von der gleichen Basisklasse erben, aber das hat nicht funktioniert.

Wie wird istringstream und ifstream einer Variablen istream zugewiesen?

+2

[Sehr ähnlich, aber mit Ausgangsströmen] (http://stackoverflow.com/q/38454951/3552770). – LogicStuff

Antwort

4

Basisklassenzeiger können auf abgeleitete Klassendaten zeigen. std::istringstream und std::ifstream sowohl von std::istream abgeleitet, also können wir tun:

//Note that std::unique_ptr is better that raw pointers 
std::unique_ptr<std::istream> stream; 

//stream holds a file stream 
stream = std::make_unique<std::ifstream>(std::ifstream{ this->_path }); 

//stream holds a string 
stream = std::make_unique<std::istringstream>(std::istringstream{}); 

Jetzt

std::string s; 
(*stream) >> s; 
+1

Ich würde wahrscheinlich 'std :: unique_ptr stream_owner;' und dann 'std :: istream & stream = * stream_owner;' verwenden, was die bekannte 'stream >> s'-Syntax erlaubt. –

+1

Die 'make_unique()' Aufrufe können etwas vereinfacht werden: 'stream = std :: make_unique (_ Pfad);' und 'stream = std :: make_unique ();' Beachten Sie auch, dass 'std :: unique_ptr' in C++ 11 neu ist, aber' std :: make_unique' in C++ 14 neu ist. –

1

Nehmen Sie eine Seite aus der Standard-Bibliothek Sie müssen nur den Inhalt extrahieren: assign nicht ein Wert; eine Referenz zuweisen Das ist wahrscheinlich das was du willst.

std::istringstream iss(stringSomething); 
std::istream& input(iss); 

Da Ströme tragen viel Staat, zu kopieren mit semantischen Fragen behaftet ist. Betrachten Sie zum Beispiel was Tellg sollte in der Kopie nach den ursprünglichen Aufrufen seekg melden. Referenzen dagegen beantworten die Frage transparent.

0

In C++ können Sie ein Objekt vom Typ Child auf eine Variable vom Typ Parent, auch wenn Child erben von Parent zuteilen. Sie können einen Zeiger Zeiger des Typs Child einem Zeiger des Typen Parent jedoch zuweisen. Möglicherweise möchten Sie die Objekte dynamisch zuweisen.

1

In C++

std::istream is; 

ist ein tatsächliches Objekt, um es Zuordnung wird die Kopie Zuweisungsoperator aufrufen, die die Subobjekt des iss kopiert, die eine IStream :: std ist in und slice es. Das Beispiel von LogicStuff verknüpft wird zeigen, dass Sie sich wie so einen Verweis oder Zeiger auf iss zuweisen müssen:

std::istream &is_ref = iss;

Die Differenz zwischen den Werten, Referenzen und Zeiger ist von grundlegender Bedeutung für C++, ich würde Ihnen raten, einen starken Griff bekommen von them.

0

std::istreamconstructed kann aus einer std::streambuf(im Allgemeinen der Vorrichtung, die Zeichen erzeugt oder verbraucht) sein.Alle i/ostream Objekte sind mit std::streambuf verknüpft und können gemeinsam genutzt werden.

std::ifstream file(this->_path); 
std::istringstream iss("str in gSo met hing"); 

std::istream A(iss.rdbuf()); // shares the same buffer device with iss 

std::string str; 

////////////// 
while(A >> str) std::cout << str << " | "; //read everything from stream (~> iss) 
std::cout << std::endl; 

A = std::move(file); 
while(A >> str) std::cout << str << " | "; //read from file, using same stream (~> file) 
+0

Im zweiten Fall sollten Sie 'A.rdbuf (file.rdbuf());' nicht aufrufen, um den Puffer zu teilen, anstatt die Eigentumsrechte zu übertragen? –

0

Sie können nicht auf einen std::istream zuweisen, aber Sie können so zu einer Referenz binden:

#include <string> 
#include <sstream> 
#include <fstream> 
#include <iostream> 

std::istringstream test_data(R"~(

some test data here 
instead of in an external 
file. 

)~"); 

int main(int, char* argv[]) 
{ 
    // if we have a parameter use it 
    std::string filename = argv[1] ? argv[1] : ""; 

    std::ifstream ifs; 

    // try to open a file if we have a filename 
    if(!filename.empty()) 
     ifs.open(filename); 

    if(!ifs) 
    { 
     std::cerr << "Error opening file: " << filename << '\n'; 
     return EXIT_FAILURE; 
    } 

    // if we have an open file bind to it else bind to test_data 
    std::istream& is = ifs.is_open() ? static_cast<std::istream&>(ifs) : test_data; 

    // use is here 
    for(std::string word; is >> word;) 
    { 
     std::reverse(word.begin(), word.end()); 
     std::cout << word << '\n'; 
    } 
}