std::cout 定义在哪里?

4

我想了解它是如何工作的...

<iostream> 头文件中,存在 namespace std

#include <ios>
#include <streambuf>
#include <istream>
#include <ostream>

namespace std {
  extern istream cin;
  extern ostream cout;
  extern ostream cerr;
  extern ostream clog;
  extern wistream wcin;
  extern wostream wcout;
  extern wostream wcerr;
  extern wostream wclog;
}

因此,cout是类型为ostream的对象的名称,并且由于extern的原因,在另一个文件中定义。好的。

当我在我的简单程序中尝试创建ostream对象时,我无法这样做,因为ostream类的构造函数是protected的。好的。

那么,我该如何创建(定义)一个在外部文件中具有protected构造函数且看起来像全局变量的对象呢?


1
你可以将std::cout视为单例模式。 "这些对象保证在构造std::ios_base :: Init类型的对象期间或之前进行初始化,并且可以在具有有序初始化的静态对象的构造函数和析构函数中使用(只要在定义对象之前包含<iostream>)"。 - Alessandro Teruzzi
在iostream头文件中有命名空间std:您正在浏览libstdc++吗?该文件顶部没有许可证信息吗? - KamilCuk
2
标准流对象的确切定义时间、位置和方式是实现细节,与它们的使用无关。如果你在创建自己的流对象方面遇到了具体问题,请直接询问相关内容。 - Some programmer dude
1
@AlessandroTeruzzi 谢谢您的回答。我知道我可以将cout视为单例模式。但是我仍然不知道如何在我的项目中创建类似的东西。我知道如何创建单例,但是当我想要写一些内容时,例如"Hello World!",我必须编写getSingleton() << "Hello World!"。我希望避免使用括号。 - juga92
C++标准库包含许多头文件和一个二进制库(libstdc++用于gcc,libc++用于clang),实际的cout对象大多数情况下在二进制部分中。没错,在这里。,使用显式构造函数和此处定义的存储进行放置new操作。 - user14215102
显示剩余3条评论
1个回答

5

libstdc++是由gcc使用的库,它是如何工作的:

cout的存储定义为类型为fake_ostream的全局变量,可能可以无问题地构造。 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/globals_io.cc

然后,在库初始化期间,使用显式构造函数通过放置new语法进行重写。 https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/c%2B%2B98/ios_init.cc

其他编译器有自己的库,并且可能使用不同的技巧。检查clang使用的libc++源代码留给读者作为练习。


谢谢您的回答。这很完美,但我仍然不明白。我看到创建了新类型(这是char[sizeof(ostream)]),然后使用该新类型定义了新对象(名称为cout)。在另一个文件中,使用extern声明了cout,但使用的类型是ostream。怎么做到的?当我尝试这样做时,出现错误“使用不同类型重新声明xxxx(我的对象名称):std:ostream vs char[272]”。 - juga92
@juga92 我认为globals_io.cc中的注释Iff <iostream> is included, these definitions become wonky就是这个意思。真正的声明(extern ostream cout)和虚假的定义(fake_ostream cout)不应该在一个编译单元中相遇。如果你在一个文件中定义了一个名为cout且大小正确的东西,而另一个文件正在请求一个外部cout,链接器将连接这两个文件。对于数据,只有在链接期间检查名称,没有办法比较类型。 - user14215102
我相信如果你搜索“C++编译和链接”,会有比我的更好的解释。还有图片... - user14215102

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