解開一個困擾自己多時的小問題
小序
今天上班的時候問了一起工作的 Sidney 同學(xué)一個小問題,顯然他是研究過了的,不過他當(dāng)時沒有給出我答案。這個問題著實困擾了我好長時間捏 ~~
晚上吃的小蔥蘸醬,呵呵,吃完之后氣兒順了、腦子也清醒了許多,想起這個問題沒搞定,于是順著 Sidney 同學(xué)提供的線索把問題搞明白了。
正文
問題是這樣的……
相信下面這個程序凡是會寫 C++ 程序的同仁都認(rèn)得, 估計學(xué)會的第一個 C++ 程序就是它了吧:
//----------------------------------------------
//
水之真諦
// http://blog.csdn.net/FantasiaX
//----------------------------------------------
#include
<iostream><br></iostream>
int
main(
int
argc,
char
*argv[])
{
std::cout "Hello, World."
return
0;
}
我 會寫一點 C 語言的程序,于是在寫這個程序的時候就對很多東西“想當(dāng)然”了。比如對于操作符“ ”,在心里一直是與 C 語言的 printf() 函數(shù)對應(yīng)起來的——認(rèn)為它就是封裝進了 ostream 對象中的 printf() 函數(shù)。既然是這樣,那么對于“ endl ”,自然就“想當(dāng)然”地認(rèn)為它是“ \n ”了。
突然有一天,在
Visual Studio
彈出的代碼自動完成窗口中發(fā)現(xiàn),
endl
不是一個成員變量(如果它代表一個字符,那么理應(yīng)是一個字符類型的成員變量)而是一個成員函數(shù)!大腦中立刻蹦出一個解釋:或許
endl
函數(shù)的返回值是字符“
\n
”吧?可是這個答案存活了不到一秒鐘就被否定了——如果想讓一個函數(shù)執(zhí)行從而得到它的返回值,應(yīng)該是調(diào)用這個函數(shù),所以寫法應(yīng)該是“
std::endl()
”而不是“
std::endl
”。寫成“
std::endl
”是將函數(shù)名放在這里,并不是在調(diào)用這個函數(shù)。哈
~~
腦子里的概念開始互相打架了
~~
因為問題是出在了
endl
上,所以一直在查
endl
的定義——結(jié)果除了發(fā)現(xiàn)
MSDN
里有個
Bug
之外,一無所獲
L
MSDN 里是這樣聲名的:
template
class<_elem _tr></_elem>
basic_ostream<_elem _tr>& endl( basic_ostream<_elem _tr>& _Ostr );</_elem></_elem>
紅色標(biāo)記的地方寫錯了
:p
C++ ISO 文檔里是這樣聲名的:
template <class chart class traits><br></class> basic_ostream<chart>& endl(basic_ostream<chart>& os);</chart></chart>
按
MSDN
里模板的“寫法”根本編譯不過去,呵呵。
不過,
MSDN
里的說明還是非常有用的——
Terminates a line and flushes the buffer.
可是函數(shù)的功能是“結(jié)束一行并沖洗緩沖區(qū)”,如果想執(zhí)行這個功能,應(yīng)該是調(diào)用這個函數(shù)、應(yīng)該寫
endl()
而不是
endl
啊……看來問題又繞回去了。于是這事兒就放下了。
今天遇到高手 Sidney ,又問起了這個問題。 Sidney 是研究過這個問題的,雖然沒有給出我答案,但他提到這么一句話——“ ”操作符是被重載過的,可以接收一個函數(shù)作為參數(shù)。正好前幾天我在寫《深入淺出話回調(diào)》的時候?qū)戇^類似的程序,經(jīng) Sidney 一點撥,頓時感覺豁然開朗。很快問題的答案就找到了——
1. 先查看 <iostream></iostream> 的成員,找到一個全局對象 cout
2. 查看 cout 對象,發(fā)現(xiàn)它是 ostream 的一個實例
3. 查看 <ostream></ostream> 文件說明中的“ ”操作符,有 10 個重載,但是沒有可將函數(shù)作為參數(shù)的
4. 仔細(xì)想了想,會不會是從別處繼承來的呢? (操作符其實就是簡寫了的函數(shù),完全可以當(dāng)函數(shù)來對待)
5. 查看 MSDN ,發(fā)現(xiàn) ostream 是由類模板 basic_ostream<char char_traits> ></char> 生成的
6. 查看 basic_ostream<char char_traits> ></char> 的說明,發(fā)現(xiàn)它也具有“ ”操作符,并且有 15 個重載。
7.
其中的一個卸載形式是——
basic_ostream& operator
說明
cout
的
操作符可以接受一個函數(shù)指針(函數(shù)的地址)作為參數(shù)。
這個重載正好與
endl
函數(shù)的聲名相匹配,所以
后面是可以跟著
endl
的,也就是說,
cout
對象的
操作符接受到
endl
函數(shù)的地址后會在后臺調(diào)用
endl
函數(shù),而
endl
函數(shù)會結(jié)束當(dāng)前行并沖洗
buffer
。
最后啰嗦一句——你可能會問:不是函數(shù)指針嗎?為什么不寫“ std::cout ”而寫“ std::cout ”呢?實際上,函數(shù)名本身就代表的是函數(shù)的地址, &endl 與 endl 的值是一樣的 J
不信你試試下面的代碼,結(jié)果與上面的一樣:
//----------------------------------------------
//
水之真諦
// http://blog.csdn.net/FantasiaX
//----------------------------------------------
#include
<iostream><br></iostream>
int
main(
int
argc,
char
*argv[])
{
std::cout "Hello, World."
return
0;
}
致謝
感謝 Sidney ——謝謝你對我技術(shù)上的指導(dǎo)。更重要的是你提醒了我學(xué)習(xí)的方面——不要只把眼睛盯在一個地方,還要看到與它相關(guān)聯(lián)的事物。還有就是要多看書,我看的書還是太少了。
博文視點就要三周年慶典了,也祝博文視點的朋友們?nèi)f事如意、工作順利、身體健康!
法律聲明 : 本文章受到知識產(chǎn)權(quán)法保護,任何單位或個人若需要轉(zhuǎn)載此文,必需保證文章的完整性(未經(jīng)作者許可的任何刪節(jié)或改動將視為侵權(quán)行為)。若您需要轉(zhuǎn)載,請務(wù)必注明文章出處為 CSDN 以保障網(wǎng)站的權(quán)益;請務(wù)必注明文章作者為 劉鐵猛 ( http://blog.csdn.net/FantasiaX ),并向 liutm@beyondsoft.com 發(fā)送郵件,標(biāo)明文章位置及用途。轉(zhuǎn)載時請將此法律聲明一并轉(zhuǎn)載,謝謝!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
