如何将istringstream和ifstream分配给一个istream变量?

13

我希望拥有一个类型为istream的变量,它可以保存文件或字符串的内容。如果没有指定文件,那么这个istream类型的变量将被赋予一个字符串。

std::ifstream file(this->_path)

std::istringstream iss(stringSomething);

std::istream is

我尝试将它们分配给与同一基类继承的其他对象一样的istream变量,但那不起作用。

如何将istringstreamifstream分配给istream变量?


6个回答

11

基类指针可以指向派生类数据。std::istringstreamstd::ifstream 都是从 std::istream 派生出来的,因此我们可以这样做:

//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{});

现在你只需要使用提取内容的方法

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

2
我可能会使用 std::unique_ptr<std::istream> stream_owner; 然后 std::istream& stream = *stream_owner;,这样就可以使用熟悉的 stream >> s 语法了。 - Mooing Duck
3
make_unique() 调用可以简化一下:stream = std::make_unique<std::ifstream>(_path);stream = std::make_unique<std::istringstream>(); 此外请注意,std::unique_ptr 是 C++11 中的新特性,但 std::make_unique 是 C++14 中的新特性。 - Remy Lebeau

8

你不能给std::istream赋值,但是你可以像这样绑定一个引用:

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

    // This will ONLY fail if we tried to open a file
    // because the filename was not empty    
    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';
    }
}

2
这正是我一直在寻找的:一个完整的示例,用于选择默认流(例如 std::cin),如果没有提供文件,则将其分配给类型为 std::istream 的变量。 - Parker
谢谢,这是网络上唯一的解决方案。 - Sabuncu

1
在C++中,即使Child继承自Parent,也不能将Child类型的对象赋值给Parent类型的变量。但是,您可以将Child类型的指针分配给Parent类型的指针。您可能需要考虑动态分配对象。

1

在C++中

std::istream is;

实际上,它是一个对象,对其进行赋值将调用复制赋值运算符,该运算符将iss的子对象(即std::istream)复制到is中并对其进行slice。LogicStuff提供的示例将显示您需要像这样分配iss的引用或指针:

std::istream &is_ref = iss;

值、引用和指针之间的区别是C++的基础知识,我建议您牢固掌握它们


1
从标准库中借鉴一个方法:不要赋值,而是赋予引用。这可能是您想要的方式。
std::istringstream iss(stringSomething);
std::istream& input(iss);

由于流具有很多状态,复制它们会引起语义问题。例如,考虑在原始调用seekg后,tellg在副本中应报告什么。相比之下,引用透明地回答了这个问题。


1

std::istream可以从std::streambuf(基本上是生成或消耗字符的设备)构建。所有i/ostream对象都有一个相关联的std::streambuf,可以共享使用。

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)

在第二种情况下,你不应该调用 A.rdbuf(file.rdbuf()); 来共享缓冲区而不是转移所有权吗? - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接