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