std :: cout声明如何工作?

时间:2015-10-13 18:56:52

标签: c++ cout

std::cout对象在iostream头文件中声明为

namespace std _GLIBCXX_VISIBILITY(default)
{
...
extern ostream cout;
...
}

从现在开始,我放弃了std::前缀。

所以,据我所知,cout是&#34;只是&#34;类型为ostream的对象。我开始想知道为什么用cout而不是其他ostream对象打印到屏幕的东西,所以我试图创建一个ostream类型的对象,但编译器不会让我。事实上,ostream只是basic_ostream<char>的别名,并且该类型的默认构造函数受到保护。很好,我想。但后来我想知道:为什么cout的声明合法开始?为什么不发出编译错误?

我再次尝试使用关键字ostream声明extern,例如

extern ostream os;
os << "Will you compile?\n";

这次我得到了os的未定义引用错误。然后问题就转移到以下问题:是否有一个&#39;定义&#39;其他地方的cout?如果是这样,在哪里?

我无法理解这一点。我知道,出于性能和安全原因,标准标题是用一种“神秘的”字体写成的。方式,除非你完全掌握语言(我仍然不太可能),但并不总是易于阅读,但我想了解这一点。

感谢。

2 个答案:

答案 0 :(得分:5)

  

我开始想知道为什么用cout打印屏幕的东西而不是其他ostream对象,

因为std::cout使用与stdout设备关联的流缓冲区。

  

所以我尝试创建一个ostream类型的对象,但编译器不会让我。事实上,ostream只是basic_ostream的别名,并且该类型的默认构造函数受到保护。很好,我想。但后来我想知道:为什么宣布cout合法开始?为什么不发出编译错误?

因为它是一个声明,而不是一个定义,所以它不会调用任何构造函数。也许您应该阅读extern对声明的含义。

extern声明只是说在程序中的某个地方定义了一个对象ostream并且称为cout。由于您实际上没有提供任何此类定义,因此会出现链接器错误。

要近似模拟std::cout,您可以在某个.cpp文件中执行此操作:

namespace {
  std::ofstream fake_cout("/dev/stdout");
}
std::ostream cout(fake_cout.rdbuf());

这会创建一个写入fstream的{​​{1}},然后将名为/dev/stdout的{​​{1}}与其流缓冲区相关联。

这不是对真实ostream的良好模拟,因为它不能确保在任何其他全局变量尝试使用它之前初始化流,这是真实的。

答案 1 :(得分:4)

  

是否有&#39;定义&#39;在其他地方的cout?如果是这样,在哪里?

是的,标准C ++库的libstdc ++实现中有cout的定义。该定义不是以在标准C ++中有效的方式完成的。没关系,因为标准C ++库的实现不必用标准C ++编写,只需要以实现其余部分理解的方式编写。