【C/C++】string s(string())
標題中這句代碼,是前兩天在另一個視頻下面提起的,如果不做提示也不做測試,大家可以先猜猜這行代碼表示什么意思,例如這樣寫輸出啥:
測試結(jié)果:
輸出是“1”
從gcc的警告輸出,這應(yīng)該是一個坑,使得即便在沒有任何“-W”選項下它也主動提醒了,警告中也回答了上面的問題:這句語句是一個“function declaration”,也就是一個函數(shù)聲明,cout輸出一個函數(shù)時,是轉(zhuǎn)為bool值true,也就是輸出1了
如果事先不知道這點,90%以上的人對這行代碼的理解都會認為是一個變量定義,是通過string的臨時對象來構(gòu)造s這個string,但編譯器顯然不這么想
先來說下s為什么是一個函數(shù),寫成這樣應(yīng)該看得更清楚一些:
s這個函數(shù)返回string,有一個輸入?yún)?shù),輸入?yún)?shù)是一個函數(shù)指針,其指向一個無參數(shù)并返回string的函數(shù)
那么為什么可以寫成標題那樣呢,首先,C和C++規(guī)定函數(shù)聲明中,參數(shù)可以只寫類型,不寫參數(shù)名,例如void f(int a),可以省掉a,寫成void f(int),所以上面定義中的p可以省略了:
接下來是一個相對冷的知識,首先很多人應(yīng)該知道,在C和C++中,“函數(shù)”和“函數(shù)指針”是兩個類型概念,它們并不等價:
但是,函數(shù)聲明或定義的時候,參數(shù)類型是一個特例,和上面這個“f”不同,這個“f”雖然寫在“main”函數(shù)體內(nèi),但依然是個聲明,只是告知其下的代碼有這么個樣子的函數(shù),“f”并不是“main”的局部變量,但是如果作為函數(shù)參數(shù),由于參數(shù)必然是一個局部變量,所以如果其指代一個函數(shù),則必然是函數(shù)指針,所以,參數(shù)類型如果“寫作”一個函數(shù)樣式,會被視為對應(yīng)的指針:
這里可以看到,作為g的兩個參數(shù),雖然“f”和“pf”的寫法不同,但是類型是相同的,換句話說,參數(shù)如果是函數(shù)指針,則“*”可以省略
然后我們把上面那個去掉了“p”的定義中的“(*)”也去掉,不就成了:
so,s是一個函數(shù),就是這個原理
雖然這個例子比較極端(實踐中并不會這樣寫),但總會有一些復(fù)雜的情況存在,特別地,在使用無參默認構(gòu)造的時候,不要加括號:
不過,如果是“new”的話,寫不寫都可以:
因為函數(shù)類型沒有size也無法構(gòu)造,所以“new A()”是用無參構(gòu)造一個A的新對象,而不是函數(shù)“A()”的一個新實例(沒法憑空造這個函數(shù)實例)
但是從習慣上,這種時候也還是別加括號了
回到標題,如果真的需要用string的臨時對象構(gòu)造s這樣一個string變量,警告信息中也給了推薦的辦法:
給參數(shù)多加一層括號,這樣編譯器就會將其視為表達式“string()”,而非函數(shù)類型“string()”了
語法上將標題的s解析為函數(shù)聲明,這一系列原因帶有C語言的風格,實際上也正是C++語法在C基礎(chǔ)上發(fā)展導(dǎo)致的,在C語言中并不會出現(xiàn)這種情況,因為標準C中,類型后面加圓括號只可能是表示函數(shù)類型,而且由于結(jié)構(gòu)體類型強制需要“struct”關(guān)鍵字前綴,也不可能出現(xiàn)C++中的名字二義性(但是某些C擴展允許省略struct關(guān)鍵字,于是就有可能有問題了)