一、引子
std::cout << "Hello, world" << std::endl;
以上,作为任何一名接触过C++编程的朋友们来说,基本应该都是自己写下的第一行代码吧(别钻牛角尖,说什么头文件啥的)。
也许你也曾心里疑惑过,std::cout
这也不是函数的表示方式啊,为啥他能这么写?也许你的老师也跟你说过,记住这个固定句式,它就这么写!然后,没有然后。你就这样已知遵循着“谆谆教诲”,教条式的传用了整个职业生涯~
本篇,作为打破你的思维,开始刨根问题的第N次分享,我们尽量深入浅出,更多的了解下std::cout << "Hello, world" << std::endl;
,做到知其然,知其所以然。
二、鱼游浅底
2.1 cout
是什么?
extern _CRTDATA2_IMPORT ostream cout;
cout
是什么? 对,它ostream
类型的实例对象,而且是extern
修饰的全局对象。
所以,既然是实例对象,我们还可以这样使用:
使用示例
#include <iostream>
int main() {
std::ostream& out = std::cout; // std::cout is an instance of std::ostream
out << "Hello, World!" << std::endl;
return 0;
}
2.2 cout
为何能直接 接<<
操作符 ?
对象后面 直接接 <<
操作符,这个不难联想,自然是有实现 <<
操作符。
所以,我们简单看看ostream
类
using ostream = basic_ostream<char, char_traits<char>>;
ostream
是 basic_ostream<char, char_traits<char>>
的一个类型别名。我们简单了解 下basic_ostream
类模板及其相关组件。
-
basic_ostream
类模板:basic_ostream
是 C++ 标准库中的一个类模板,用于表示输出流。它是一个通用的流类,可以与不同的字符类型和字符特性(traits)一起使用。- 模板参数包括字符类型(如
char
或wchar_t
)和字符特性类(如char_traits<char>
)。
-
char
:char
是 C++ 中的基本数据类型,用于表示单字节字符。- 在
basic_ostream<char, char_traits<char>>
中,char
指定了流处理的字符类型。
-
char_traits<char>
:char_traits
是一个特性类模板,定义了如何处理特定字符类型的操作。char_traits<char>
提供了一组静态成员函数和类型,用于描述char
类型字符的特性和操作,如比较、复制、查找等。
-
using
声明:using ostream = basic_ostream<char, char_traits<char>>;
是一种类型别名声明。- 它将
basic_ostream<char, char_traits<char>>
类型重命名为ostream
,使得代码更简洁和易读。
2.3 basic_ostream
在上面2.2 中我们已经了解到,iostream
其实只是类模版basic_ostream
特化类型basic_ostream<char, char_traits<char>>
的别名,那么回到我们最开始的问题,为何能直接使用<<
操作符连接使用,答案不言而喻,必然存在<<
的操作符函数,而且是多个函数的重载!!
说这话,我必然是有依据的。这里我为大家附上部分basic_ostream
中的代码:
basic_ostream& __CLR_OR_THIS_CALL operator<<(
basic_ostream&(__cdecl* _Pfn)(basic_ostream&) ) {
// call basic_ostream manipulator
return _Pfn(*this);
}
basic_ostream& __CLR_OR_THIS_CALL operator<<(_Myios&(__cdecl* _Pfn)(_Myios&) ) {
// call basic_ios manipulator
_Pfn(*this);
return *this;
}
basic_ostream& __CLR_OR_THIS_CALL operator<<(ios_base&(__cdecl* _Pfn)(ios_base&) ) {
// call ios_base manipulator
_Pfn(*this);
return *this;
}
basic_ostream& __CLR_OR_THIS_CALL operator<<(bool _Val) {
// insert a boolean
ios_base::iostate _State = ios_base::goodbit;
const sentry _Ok(*this);
if (_Ok) {
// state okay, use facet to insert
const _Nput& _Nput_fac = _STD use_facet<_Nput>(this->getloc());
_TRY_IO_BEGIN
if (_Nput_fac.put(_Iter(_Myios::rdbuf()), *this, _Myios::fill(), _Val).failed()) {
_State |= ios_base::badbit;
}
_CATCH_IO_END
}
_Myios::setstate(_State);
return *this;
}
basic_ostream