如何创建自己的类,其行为完全相同:std::cout
& std::cerr
。
我正在编写一个迷你操作系统,这是一个要求,将这些作为模块存在。
代码如下:
myNewCoutClass myCout; // create cout behavioral class
myNewCerrClass myCerr; // create cerr behavioral class
myCout << someString << endl; // prints the string
myCerr << someString << endl; // prints the string as error
答案 0 :(得分:2)
这些对象是std::ostream
个。您可以创建自己的std::ostream
。确切地说,它的工作方式完全取决于您尚未指定的数据接收器,但std::ostringstream
足以让您开始测试使用它的代码。
但是,如果你真的希望重新发明std::cout
,不要。它的数据接收器是魔术文件句柄 stdout ,您无法重新创建它,因为它是由操作系统提供的。您可以创建std::ostream
从std::cout
窃取缓冲区,但重点是什么?
答案 1 :(得分:0)
首先, 不 执行此操作,除非您知道非常以及您正在做什么,并且愿意承担所有涉及的风险。它只是一个例子,说明如何将另一个流绑定到stdout
,实际上创建第二个cout
,作为思想实验。那就是说,我们走了。
如果你想为stdout
创建另一个流,你必须好好看看你的编译器的深刻内脏,并找出它如何定义cout
,{{ 1}}和/或cerr
。这将位于编译器相关的位置,很可能不在您期望的位置;例如,在旧版本的Visual Studio中,您必须查看clog
文件夹中的一些文件:
crt\src
由此,我们可以为// Visual Studio 2010 implementation of std::cout.
// Irrelevant parts omitted.
// cout.cpp
__PURE_APPDOMAIN_GLOBAL static filebuf fout(_cpp_stdout);
#if defined(_M_CEE_PURE)
__PURE_APPDOMAIN_GLOBAL extern ostream cout(&fout);
#else
__PURE_APPDOMAIN_GLOBAL extern _CRTDATA2 ostream cout(&fout);
#endif
struct _Init_cout
{
__CLR_OR_THIS_CALL _Init_cout()
{
_Ptr_cout = &cout;
if (_Ptr_cin != 0)
_Ptr_cin->tie(_Ptr_cout);
if (_Ptr_cerr != 0)
_Ptr_cerr->tie(_Ptr_cout);
if (_Ptr_clog != 0)
_Ptr_clog->tie(_Ptr_cout);
}
};
__PURE_APPDOMAIN_GLOBAL static _Init_cout init_cout;
// stdio.h
#define _INTERNAL_BUFSIZ 4096
// ...
#define _IOB_ENTRIES 20
// ...
#ifndef _STDSTREAM_DEFINED
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])
#define _STDSTREAM_DEFINED
#endif /* _STDSTREAM_DEFINED */
// _file.c
char _bufin[_INTERNAL_BUFSIZ];
FILE _iob[_IOB_ENTRIES] = {
/* _ptr, _cnt, _base, _flag, _file, _charbuf, _bufsiz */
/* stdin (_iob[0]) */
{ _bufin, 0, _bufin, _IOREAD | _IOYOURBUF, 0, 0, _INTERNAL_BUFSIZ },
/* stdout (_iob[1]) */
{ NULL, 0, NULL, _IOWRT, 1, 0, 0 },
/* stderr (_iob[3]) */
{ NULL, 0, NULL, _IOWRT, 2, 0, 0 },
};
_CRTIMP FILE * __cdecl __iob_func(void)
{
return _iob;
}
// `__PURE_APPDOMAIN_GLOBAL` is an internal macro that can generally be ignored.
// `_CRTIMP` is an internal macro that can generally be ignored.
// `_CRTDATA2` is an internal macro that can generally be ignored.
// `__CLR_OR_THIS_CALL` is a calling convention macro that expands to either
// `__clrcall` or `__thiscall`.
派生自己的流,尽管它依赖于编译器。
stdout
结果......
// Visual Studio 2010 user-created char16_t cout.
// Note that in VStudio 2010, char16_t is actually a typedef for unsigned short.
#include <iostream>
#include <fstream>
#include <string>
#include <codecvt>
#define _cpp_stdout (&(__iob_func())[1])
typedef std::basic_filebuf<char16_t, std::char_traits<char16_t>> filebuf_c16;
typedef std::basic_ostream<char16_t, std::char_traits<char16_t>> ostream_c16;
int main() {
filebuf_c16 f16out(_cpp_stdout);
ostream_c16 c16out(&f16out);
// It really should be tied to the other stdin/stdout/stderr streams,
// but this is a simple program where it won't be a problem.
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
std::string u8tmp = "Hello from char16_t!";
std::u16string u16str = converter.from_bytes(u8tmp);
c16out << u16str << std::endl;
}
如果您想将第二个标准Hello from char16_t!
(a.k.a。与ostream
)绑定到basic_ostream<char, char_traits<char>>
,您可以使用类似的内容。请注意,由于stdout
为fout
,您需要制作自己的static
。还要注意,这只是在寻找麻烦,但这不是重点;只是要小心数据竞赛或类似的任何事情。
请注意,虽然可以这样做,但除非您非常了解自己所做的事情,否则愿意为出现问题的任何事情负责,并愿意花足够的时间来钻研在编译器的库和/或代码中找出它是如何实现filebuf
和默认字符串的,你很好不应该这样做。
另请注意,您的代码将与编译器紧密耦合,并且同一编译器的未来版本可能会破坏它。例如,据我所知,由于CRT的更改,此代码不会使用Visual Studio 2015进行编译(具体来说,我相信它是因为stdout
的更改,但我没有&#39看看吧。