使用istream参数进行读取的Istream函数

3

我试图理解这段代码

istream &read(istream &is, Sales_data &item) 
{
    double price = 0;    
    is >> item.bookNo >> item.units_sold >> price;   
    item.revenue = price * item.units_sold;    
    return is;
} 

ostream &print(ostream &os, const Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " "    
        << item.revenue << " " << item.avg_price();    
    return os; 
}

我不理解这些函数是什么意思,也不明白为什么我们在读取时使用istream而在打印时使用ostream,而不是使用cincout


欢迎来到 Stack Overflow!您可以参观[tour]以了解我们网站的概述。 - L. F.
2个回答

4
要理解在readprint函数中发生了什么,您需要理解一些微妙的细节。从概述的角度来看,istreamostream是通用的输入和输出类,为C++中的流I/O提供了基础。正如其他答案和评论正确指出的那样,std::cinstd::cout派生自istreamostream,以提供对标准流stdinstdout的输入/输出。
这些流本身具有状态,该状态确定流是否良好并且可以读取或写入,或者是否发生了流错误,从而防止进一步的I/O操作(某些故障是可恢复的,某些则不是)。请参见std::basic_ios :: rdstate std::basic_ios :: setstate 以获取有关组成流状态的位(< code> goodbit,badbit,failbit,eofbit )的讨论。
现在看看您的函数原型:
istream &read(istream &is, Sales_data &item)

并且

ostream &print(ostream &os, const Sales_data &item)

请注意第一个参数是当前流的引用,返回值也是对同一流的引用。这很重要,因为它传递了对流的引用,所以函数内发生的任何对Steam State的更改都将在返回时可用。因此,如果在read函数中遇到eof,则状态的更改将在返回时可用。对于您的print函数也是如此(尽管可能会更改流的潜在错误较少且不同)。
read中,您正在从流中读取3个信息:item.bookNo、item.units_soldprice,并更新item.revenue
is >> item.bookNo >> item.units_sold >> price; 
item.revenue = price * item.units_sold;

你可以通过将 std::cin 作为 is 的参数传递来从中读取内容,或者你可以传递一个打开的文件流。流操作将适用于任何有效的流。 print函数的作用与之相反,它输出item.isbn()、item.units_sold、item.revenue以及item.avg_price()的返回值作为输出。如果将std::cout作为os传递。
两个函数中的最后一个命令返回包括流状态更改在内的流,因此调用者可以检查readprint是否成功。这对于调用者能够确定I/O是否发生非常关键。
过度简化的示例可能有助于理解这些概念。在这里,我们声明了一个简化的结构体Sales_data,其中包含int bookno, units_sold;double price, revenue;等元素。例如:
#include <iostream>

struct Sales_data
{
    int bookno, units_sold;
    double price, revenue;
};

我们将简化read函数,仅读取bookno, units_soldprice这三个参数,并计算单个项目的revenue,例如:
std::istream &read(std::istream &is, Sales_data &item) 
{
    is >> item.bookno >> item.units_sold >> item.price;   

    item.revenue = item.price * item.units_sold;    

    return is;
} 

简化 print 函数,只输出 units_soldrevenue:

std::ostream &print(std::ostream &os, const Sales_data &item)
{
    os << "units sold: " << item.units_sold << " revenue: $"  << item.revenue << '\n';

    return os; 
}

现在您可以非常简单地提示用户输入bookno、units_soldprice,以展示readprint函数的工作方式,以及一个函数内部发生错误如何改变流状态。下面是一个简短的main()函数:

int main (void) {

    Sales_data sd;

    std::cout << "enter bookno units_sold price: ";

    if (read (std::cin, sd))        /* if read succeeds */
        print (std::cout, sd);      /* print data */
    else
        std::cerr << "error: invalid input\n";
}

示例使用/输出

$ ./bin/readprintstream
enter bookno units_sold price: 12 100 12.95
units sold: 100 revenue: $1295

或者发生错误时:

$ ./bin/readprintstream
enter bookno units_sold price: 23 banannas 12.28
error: invalid input

希望这次讨论和示例能够帮助您更好地理解这个概念。如果您有进一步的问题,请告诉我。


这个例子非常有帮助!!!现在我的问题更加清晰了。谢谢! - Stephen Gregory
基本上,参数 istream &is 是 cin 的引用。(cin 和 &is 都是 istream 的实例) - Stephen Gregory
没错。你可以传入任何你想要read读取的流。在上面的例子中,它是std::cin,也可以是一个打开的文件流。通常情况下,我们使用重载的<<>>运算符来实现,而不是编写readprint函数,但两者都可以。请参见Can't load correct information from file以获取最近重载<<>>的示例。 - David C. Rankin

3

std::cinstd::coutstd::istreamstd::ostream的特定实例。因此,您可以调用这些函数并将std::cinstd::cout作为要使用的流传递。这使得函数更具通用性,因为我们可以使用流进行更多操作,而不仅仅是命令行输入和输出。

特别地,std::ifstreamstd::ofstream用于文件I/O,std::istringstreamstd::ostringstream用于字符串I/O。


2
我们不仅可以用流来进行命令行输入和输出,而且还可以使用 std::[i|o]fstream 进行文件 I/O 和 std::[i|o]stringstream 进行字符串 I/O。 - L. F.
好的澄清。我把它偷了过来加到我的答案里 :) - JohnFilleau

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