众所周知,有些图书馆使用iostream
和fstream
等流。
我的问题是:
print
,fgets
等相似的功能(例如)?他们需要自己的运算符<<
和>>
,但他们所做的一切都可以用上面的简单函数实现,也可以用函数
printf("Hello World!");
对我来说比
更具可读性和逻辑性cout << "Hello World";
我还认为C ++中的所有字符串抽象都编译为二进制的(效率较低的)标准函数调用。
答案 0 :(得分:24)
Streams具有更好的类型安全性。
例如printf("%s", a);
如果a
是整数,则可能会出现严重错误。 cout << a;
没有这个问题。
另一个问题是流更好地符合面向对象的设计方法。
例如,您有一个简单的应用程序写入一些输出,然后您希望输出转到文件而不是控制台。使用C来电,您必须将对printf
的所有来电替换为对fprintf
的来电,并注意保持FILE*
。使用流只需更改您正在使用的流的具体类,就是这样,大多数代码都保持相同:
void doSomething(ostream& output)
{
output << "this and that" << a;
}
doSomething(cout);
doSomething(ofstream("c:\file.txt"));
答案 1 :(得分:9)
首先,它允许您利用C ++对象模型来创建不关心它们是写入标准输出,文件还是网络套接字的函数(如果您有一个派生自{的网络套接字{1}})。 E.g。
ostream
类似于输入流。
Streams在输入和输出对象方面也有优势。如果您想使用void outputFoo(std::ostream& os)
{
os << "Foo!";
}
int main()
{
outputFoo(std::cout);
std::ofstream outputFile("foo.txt");
outputFoo(outputFile);
MyNetworkStream outputSocket;
outputFoo(outputSocket);
}
读取对象会发生什么?
scanf
即使有适当的说明符,MyObject obj;
scanf("??", &obj); // What specifier to use?
如何知道如何填写对象的成员?使用C ++流,您可以重载scanf
并写入
operator<<
它会起作用。类似地,对于MyObject obj;
std::cin >> obj;
,您可以在一个地方编写对象序列化代码,而不必在其他任何地方担心它。
答案 2 :(得分:7)
C ++流是类型安全的。在C中,如果你说:
double d = 1.23;
printf( "%d", d );
即使转换不正确,也不能保证收到错误消息。
您似乎在问非常基本的C ++问题。你使用哪种C ++教科书不包括它们?
答案 3 :(得分:5)
printf对一个人来说不是类型安全的。 cout界面也更通用,这允许printf版本无法使用很多东西。一个很好的例子是你的类型的流操作符,如果你正确的话,将std :: ostream称为流,而不是cout。因此,您只需使用不同的流即可更改输出的目标。要使用printf执行此操作,您必须执行大量依赖于平台的输出句柄覆盖。
我还认为C ++中的所有字符串抽象都编译为二进制的(效率较低的)标准函数调用。
想想你想要的一切。在你真正测试你的假设之前,你的意见不会太重。此外,您需要考虑抽象的丢失,这在现代软件开发中通常更为重要。
答案 4 :(得分:3)
除了类型安全和多态之外,流更便携。在某些系统上,带有long的printf需要“%d”,而在某些系统上则需要“%ld”。
答案 5 :(得分:2)
Streams可以链接在一起
cout << "hello" << " " << "world"
答案 6 :(得分:2)
流的另一个好处是它们可以扩展。使用流,您可以让用户定义的类像内置类型一样工作:
class foo { ... };
ostream &operator<<(ostream &ostr, const foo &f)
{
ostr << ... how you want to print a foo ...;
return ostr;
}
现在你可以像其他任何东西一样打印foo:
int n = ...
foo f = ...
cout << n << ": " << f << endl;
答案 7 :(得分:2)
C ++ IOStreams 非常低效(在我所知的大多数实现中)。通常,这不是一个问题,但当它时,库基本上是无用的。这也是一个很好的观点,语法不直观(而且非常非常冗长)。图书馆很复杂,不必要地难以扩展。它也不是很灵活。与STL之类的东西形成鲜明对比的是,IOStreams真的看起来像个糟糕的梦。但它就在这里,我们坚持下去。
它在这里的原因,以及它看起来的原因,是它是在C ++成熟语言之前开发的。在我们有数十年的经验告诉我们什么是和不是好的图书馆设计之前。在任何人真正知道选项是什么之前。
C ++需要一个比C更好的I / O库。在某些重要的方面,C ++ IOStreams 更好。正如其他人所提到的,它们是类型安全的和可扩展的。通过实现单个运算符,我可以打印出用户定义的类。 printf
无法做到这一点。我也不必担心格式说明符错误,并且由于缺乏类型安全性而打印出垃圾。
需要修复所需的。嘿,在早期,虚函数和运算符重载是 the shit 。看起来很酷。当然,图书馆想要使用这些功能。
IOStreams库是以下之间的妥协:
stdio.h
图书馆没有实现所有这些,我相信今天,凭借我们几十年的语言经验,我们可以设计出更好的图书馆。但是在90年代中期,当他们正在寻找要添加的I / O库时,这是他们能找到的最好的。
答案 8 :(得分:1)
带有operator<<
和operator>>
的流式语法允许很好的连接。
printf("%d%d%d%d%d", a, b, c, d, e);
VS
cout << a << b << c << d << e;
此外,在第一种方法中,必须始终考虑类型,而在流方法中,不得指定类型。
答案 9 :(得分:1)
实际上
cout << "Test: " << test << endl;
对我来说似乎比
更直观printf("Test: %d\n", test);
如果你以前从未像现在这样,那么你就无法知道那是什么了。
在任何一种情况下,
print "Test: " + test
(在几种语言中,包括Python :()使更多更有意义:)
答案 10 :(得分:1)
C ++允许你使用printf。所以如果你喜欢它,请继续使用它。
Streams比将输出写入控制台要多得多。它们是一种通用数据缓冲解决方案,可应用于从屏幕输出到文件处理,网络流量和输入设备接口等各种应用。你的东西可以写入(或读取)流,而无需关心数据实际发生的位置。
假设您有一个复杂的对象,您希望能够将其写入输出控制台,日志文件以及调试窗口弹出窗口。你打算写三个几乎完全相同的函数,或者你要编写一个传递(y)输出流的函数?
答案 11 :(得分:0)
我仍然使用printf,主要是因为它很容易控制输出格式。
对我来说,类型安全并不是一个主要的好处,因为它可以很容易地被测试捕获,因为基于控制台的程序比基于UI或基于Web的应用程序更容易测试。如果你不做测试,更严重的错误可以通过任何方式检查编译时间。
我也不同意索赔流因互换性而更灵活的另一个原因。它相当于建议使用fprintf(fout,...)进行互换。如果需要重定向输出,请使用管道。如果你在一个库中,为什么不只是返回一个字符串并让调用者决定它去哪里?
答案 12 :(得分:0)
stringstream
比snprintf
/ sscanf
更安全,因为它完全避免了缓冲区溢出的可能性(即使是“优雅的失败”)。
答案 13 :(得分:0)
Streams使用模板,而printf/scanf
没有。