解开一个困扰自己多时的小问题小序今天上班的时候问了一起工作的Sidney同学一个小问题,显然他是研究过了的,不过他当时没有给出我答案。" />

解开一个困扰自己多时的小问题——从std::cout

系统 1823 0
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>

解开一个困扰自己多时的小问题

小序

今天上班的时候问了一起工作的 Sidney 同学一个小问题,显然他是研究过了的,不过他当时没有给出我答案。这个问题着实困扰了我好长时间捏 ~~

晚上吃的小葱蘸酱,呵呵,吃完之后气儿顺了、脑子也清醒了许多,想起这个问题没搞定,于是顺着 Sidney 同学提供的线索把问题搞明白了。

正文

问题是这样的……

相信下面这个程序凡是会写 C++ 程序的同仁都认得, 估计学会的第一个 C++ 程序就是它了吧:



//----------------------------------------------
//
水之真谛
// http://blog.csdn.net/FantasiaX
//----------------------------------------------

#include
<iostream><br></iostream> int main( int argc, char *argv[])
{
std::cout "Hello, World."
return 0;
}


会写一点 C 语言的程序,于是在写这个程序的时候就对很多东西“想当然”了。比如对于操作符“ ”,在心里一直是与 C 语言的 printf() 函数对应起来的——认为它就是封装进了 ostream 对象中的 printf() 函数。既然是这样,那么对于“ endl ”,自然就“想当然”地认为它是“ \n ”了。

突然有一天,在 Visual Studio 弹出的代码自动完成窗口中发现, endl 不是一个成员变量(如果它代表一个字符,那么理应是一个字符类型的成员变量)而是一个成员函数!大脑中立刻蹦出一个解释:或许 endl 函数的返回值是字符“ \n ”吧?可是这个答案存活了不到一秒钟就被否定了——如果想让一个函数执行从而得到它的返回值,应该是调用这个函数,所以写法应该是“ std::endl() ”而不是“ std::endl ”。写成“ std::endl ”是将函数名放在这里,并不是在调用这个函数。哈 ~~ 脑子里的概念开始互相打架了 ~~

解开一个困扰自己多时的小问题——从std::cout和endl说起

因为问题是出在了 endl 上,所以一直在查 endl 的定义——结果除了发现 MSDN 里有个 Bug 之外,一无所获 L

MSDN 里是这样声名的:

template class<_elem _tr></_elem>
basic_ostream<_elem _tr>&amp; endl( basic_ostream<_elem _tr>&amp; _Ostr );</_elem></_elem>

红色标记的地方写错了 :p

C++ ISO 文档里是这样声名的:

template <class chart class traits><br></class> basic_ostream<chart>&amp; endl(basic_ostream<chart>&amp; os);</chart></chart>

MSDN 里模板的“写法”根本编译不过去,呵呵。

不过, MSDN 里的说明还是非常有用的—— Terminates a line and flushes the buffer. 可是函数的功能是“结束一行并冲洗缓冲区”,如果想执行这个功能,应该是调用这个函数、应该写 endl() 而不是 endl 啊……看来问题又绕回去了。于是这事儿就放下了。

今天遇到高手 Sidney ,又问起了这个问题。 Sidney 是研究过这个问题的,虽然没有给出我答案,但他提到这么一句话——“ ”操作符是被重载过的,可以接收一个函数作为参数。正好前几天我在写《深入浅出话回调》的时候写过类似的程序,经 Sidney 一点拨,顿时感觉豁然开朗。很快问题的答案就找到了——

1. 先查看 <iostream></iostream> 的成员,找到一个全局对象 cout

2. 查看 cout 对象,发现它是 ostream 的一个实例

3. 查看 <ostream></ostream> 文件说明中的“ ”操作符,有 10 个重载,但是没有可将函数作为参数的

4. 仔细想了想,会不会是从别处继承来的呢? (操作符其实就是简写了的函数,完全可以当函数来对待)

5. 查看 MSDN ,发现 ostream 是由类模板 basic_ostream<char char_traits> &gt;</char> 生成的

6. 查看 basic_ostream<char char_traits> &gt;</char> 的说明,发现它也具有“ ”操作符,并且有 15 个重载。

7. 其中的一个卸载形式是——
basic_ostream& operator
说明 cout 操作符可以接受一个函数指针(函数的地址)作为参数。
这个重载正好与 endl 函数的声名相匹配,所以 后面是可以跟着 endl 的,也就是说, cout 对象的 操作符接受到 endl 函数的地址后会在后台调用 endl 函数,而 endl 函数会结束当前行并冲洗 buffer

最后啰嗦一句——你可能会问:不是函数指针吗?为什么不写“ std::cout ”而写“ std::cout ”呢?实际上,函数名本身就代表的是函数的地址, &endl endl 的值是一样的 J

不信你试试下面的代码,结果与上面的一样:

//----------------------------------------------
//
水之真谛
// http://blog.csdn.net/FantasiaX
//----------------------------------------------

#include
<iostream><br></iostream> int main( int argc, char *argv[])
{
std::cout "Hello, World."
return 0;
}



致谢

感谢 Sidney ——谢谢你对我技术上的指导。更重要的是你提醒了我学习的方面——不要只把眼睛盯在一个地方,还要看到与它相关联的事物。还有就是要多看书,我看的书还是太少了。

博文视点就要三周年庆典了,也祝博文视点的朋友们万事如意、工作顺利、身体健康!

法律声明 本文章受到知识产权法保护,任何单位或个人若需要转载此文,必需保证文章的完整性(未经作者许可的任何删节或改动将视为侵权行为)。若您需要转载,请务必注明文章出处为 CSDN 以保障网站的权益;请务必注明文章作者为 刘铁猛 http://blog.csdn.net/FantasiaX ),并向 liutm@beyondsoft.com 发送邮件,标明文章位置及用途。转载时请将此法律声明一并转载,谢谢!




解开一个困扰自己多时的小问题——从std::cout和endl说起


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论