之前看過一些批判C++的文章,大致意思是它包含了太多的“奇技淫巧”,并不是一門好的語言。我對這個“奇技淫巧”的描述頗感興趣,因?yàn)榘凑张姓叩恼f法,C++的一些特性恰巧可以讓一些炫耀技術(shù)的同學(xué)有了炫耀的資本——畢竟路人皆知的東西卻沒什么好炫耀的。這又讓我想起了《孔乙己》中關(guān)于“回”字有幾種寫法的描述。當(dāng)時老師在上此課時,是抱著批判的態(tài)度去評價孔乙己的這種思想,而我卻感覺到這其中必有一些有意思的文化在里面——或許是“回”字演變的歷程能說明什么。所以“回”字相關(guān)的內(nèi)容讓我感覺孔乙己是個純粹和可愛的人。
寫這個系列的博文,并不是我想對C++進(jìn)行什么批判,也不是想對其進(jìn)行辯護(hù)。只是想羅列一些有意思的東西,故取名拾趣。
首先我們看下一種比較常見的技術(shù)——類構(gòu)造函數(shù)的隱式轉(zhuǎn)換。這兒先說明下,之后的例子中,我會為了盡量突出主要內(nèi)容,而忽略一些可以作為充分條件但非必要條件的東西,故設(shè)計的一些代碼存在“不完善”的嫌疑。因?yàn)闉榱硕伦∷新┒?,往往會讓整個代碼讓人感覺其重心并非在我想介紹的技術(shù)上,而在“苦行僧”式的編程原則上。
我們知道C++是一個類型嚴(yán)格的語言,比如下面一個函數(shù)
void test_int_PRoxy(const int_proxy& v) { printf("%d", v.value());} 調(diào)用者對其傳參也應(yīng)該是一個int_proxy的對象,但是實(shí)際情況并非如此。那該如何表述,我個人覺得應(yīng)該是:編譯器對其傳參應(yīng)該是一個int_proxy對象。這兩種表述的區(qū)別就是“調(diào)用者”和“編譯器”的區(qū)別。我們來看一個實(shí)際例子,我們先假定int_proxy類這么定義:class int_proxy {public: int_proxy(int n) : _m(n) {};public: int value() const { return _m; }private: int _m;}; 該類非常簡單,它有一個帶參數(shù)的構(gòu)造函數(shù),并使用參數(shù)列表形式初始化類的成員變量。 一般情況下我們都會這么調(diào)用test_int_proxy方法:
test_int_proxy(int_proxy(100)); 這種寫法我想沒人會有異議,但是如果出現(xiàn)下面這種寫法,就可能讓人感覺不可接受了: test_int_proxy(100); 然而,這種寫法對上述類的定義來說是合法的!其效果和使用int_proxy控制住是一樣的。這是為什么呢?這便是類構(gòu)造函數(shù)的隱式轉(zhuǎn)換技術(shù)。C++編譯器認(rèn)為test_int_proxy方法傳入的應(yīng)該是一個const類型的int_proxy對象,然而如果它發(fā)現(xiàn)參數(shù)不是該對象時,就會使用該類中可以使用該參數(shù)進(jìn)行構(gòu)造對象的方法構(gòu)造出一個臨時的對象。我們例子中傳參100是個int型數(shù)據(jù),而int_proxy正好有一個攜帶int參數(shù)的構(gòu)造函數(shù)。稍微總結(jié)下類構(gòu)造函數(shù)隱式轉(zhuǎn)換的必要條件:找不到傳參類型嚴(yán)格對應(yīng)的函數(shù)找到傳參類型嚴(yán)格匹配的類的構(gòu)造函數(shù)因?yàn)殡[式轉(zhuǎn)換構(gòu)造出的是臨時對象,所以不可修改,故觸發(fā)隱式轉(zhuǎn)換的函數(shù)的傳參類型必須要使用const修飾 但是個人覺得這種“奇巧淫技”還是不用為好。比如我們代碼中還有如下函數(shù):void test_int_proxy(const int& v) { printf("%d", v + 100);} 那么C++編譯器會針對傳100的調(diào)用上面這個過程。這樣一個函數(shù)調(diào)用有兩個匹配的調(diào)用方法就會產(chǎn)生不確定性——這兒指的不確定性并非是指編譯器調(diào)用哪個方法的不確定性,而是指維護(hù)這段代碼的人對上述代碼做調(diào)整時容易忽略一些問題而導(dǎo)致的“人禍”。 再比如,我們在代碼中加入下面類和方法
class int_proxy_2 {public: int_proxy_2(int n) : _m(n) {};public: int value() const { return _m + 100; }private: int _m;};void test_int_proxy(const int_proxy_2& v) { printf("%d", v.value());} 那么編譯器不能確定隱式轉(zhuǎn)換是要轉(zhuǎn)換哪個類,更不知道是調(diào)用哪個test_int_proxy方法了。 限制類構(gòu)造函數(shù)的隱式轉(zhuǎn)換的方法也很簡單,就是給對應(yīng)的構(gòu)造函數(shù)加上explict關(guān)鍵字class int_proxy {public: explicit int_proxy(int n) : _m(n) {}; 這樣通過隱式轉(zhuǎn)換而構(gòu)造臨時對象的圖謀將會被察覺并禁止。
新聞熱點(diǎn)
疑難解答
圖片精選