conversion function,轉(zhuǎn)換函數(shù)
語法:如黃色部分所示,名稱“operator+類型”,沒有參數(shù),它的返回類型要與名稱中的類型一致,并且作者不能寫出來。
non-explicit-one-argument ctor
這種構(gòu)造函數(shù),它是有兩形參,且后一個形參有初值,所以它允許被一個實參調(diào)用,后面的形參就設(shè)為默認值。
所以調(diào)用示例中,編譯器就會自動轉(zhuǎn)換,以完成編譯。
當conversion function和non-explicit-one-argument ctor并存時,調(diào)用示例中,就會有兩種可以行的完成方法,編譯器是沒法決定選擇使用哪一種的,所以這樣會報錯。
explicit-one-argument ctor
加了explicit關(guān)鍵字會讓編譯器不能將4轉(zhuǎn)為Fraction,所以這里調(diào)用時編譯器也會報錯。
class模仿指針
pointer-like classes,關(guān)于智能指針
智能指針強化了普通指針所沒有的功能,這里暫不詳述。
上面的是C++1.0標準庫簡化后的智能指針;在指針能用到的操作符就是‘*’和‘->’,所以需要重載這兩個操作符,而且是必須的。
語法: ‘*’的重載是直接返回指向的內(nèi)容;而‘->’則是返回實際的指針,但是這樣‘->’不就是消耗了嗎?然而‘->’它在C++的定義是可以重復(fù)使用的,就是說完成重載函數(shù)后,它繼續(xù)起作用。
pointer-like classes,關(guān)于迭代器
迭代器也相當于智能指針,它將指向容器的內(nèi)容;
有所不同的是會有更多的操作符重載‘++’和‘--’,這些操作符作用于指針則是用于移位(內(nèi)存地址),而這里則是改變在鏈表中的位置;
迭代器的‘*’的重載,要返回容器內(nèi)容的數(shù)據(jù);
而‘->’的重載則是返回容器內(nèi)容數(shù)據(jù)的地址(即是返回指針)。
class模仿函數(shù)
function-like classes,所謂仿函數(shù)
模仿函數(shù),即是要重載‘()’;
示例中,類模板是pair(一對的),所以寫了兩個struct,實現(xiàn)pair中兩個對象的調(diào)用。
調(diào)用:
標準庫中,仿函數(shù)所作用的奇特的base classes
在C++標準庫里面,有很多用仿函數(shù),都會繼承類似‘binary_function’的classes,它不會占用內(nèi)存(實際上可能會占用為1)。
關(guān)于namespace
由于,在實際的開發(fā)團隊中,各部門之間所寫的代碼,難免會有重名的情況出現(xiàn);
或者自己寫的測試程序也會有重名的情況,利用命名空間namespace,去解決重名情況,這樣一來就可以在不同的namespace中都使用自己習(xí)慣的名稱,不用再苦惱為變量和函數(shù)如何命名的問題。
關(guān)于模板
class template,類模板
所謂class template,就是在設(shè)計class時,把那些你認為允許使用者任意指定的類型抽出來,用自定義的關(guān)系字代替(這里用‘T’);
在調(diào)用時,就像上面一樣,把指定類型寫在‘<>’里面放在類名的后面。
語法:用template,表示T為未指定類型(可以是類,也可以是普通的數(shù)據(jù)類型)
function template,函數(shù)模板
所謂函數(shù)模板,就是允許函數(shù)不指明是哪一種類型調(diào)用和返回;
在調(diào)用時,編譯器會進行實參推導(dǎo),用來確定調(diào)用的類型;
要注意的是對象的類的功能要完善,要用到的操作符一定要重載。
語法:用template,表示T為未知的類型;
(在模板定義的語法中關(guān)鍵字class和typename的作用是完全一樣的)
member template,成員模板
所謂成員模板(也可以說是模板成員),就是說它是類的成員,而且它本身又是一個模板。
特化模板
最前面的是普通的類模板,可以接收所有的類型,稱為泛化模板;
而后面的三個則是特化模板,它是泛化模板中的特例,只能接收指定的類型;(如果泛化模板和特化模板同時存在,編譯器會先檢測特化模板)
但這樣做不是跟不用模板一樣嗎?不一樣,這樣做可以為每種類型寫不一樣的內(nèi)容。
模板偏特化(局部特化)
個數(shù)上的部分特化,將部分確定的形參類型和不確定的模板參數(shù)類型的標識符依次排序。(左邊的一定要是確定的形參類型,而不能有非模板和模板參數(shù)穿插在里面)
范圍上的局部特化,例如指針是對應(yīng)類型的部分;
上面便是實現(xiàn)方法,在調(diào)用時編譯器會判斷,是否實參為指針形,而選擇下面的一個(上一個和下一個的標識符沒有直接的關(guān)聯(lián),可以寫成右邊的)
template template parameter,模板模板參數(shù)
上面的class,就是所謂的模板模板參數(shù)的寫法,黃色的部分,是它與之不同的之處;
黃色部分表示,Container自身為模板,并且用第一模板參數(shù)‘T’作為它里面的參數(shù)類型(黃色里面的‘T’,就是指第一個模板‘T’);
但這樣是還不是調(diào)用的,還需要增加中間的兩行才可以(具體原因,會在下一個相關(guān)的章節(jié)詳述)
對于上面的例子,第二模板參數(shù)也使用第一模板參數(shù)‘T’,作為它里面的參數(shù);
但它不是模板模板參數(shù),因為它的第二模板參數(shù)是預(yù)置了默認值,不完全是模板,
在調(diào)用時,它可以不寫,而使用默認值,也可以寫(第二個調(diào)用便是),但這樣就不用理會第一參數(shù)的類型,而可以寫上需要的類型。
這一點就可以與模板模板參數(shù)的定義分開。
關(guān)于C++標準庫
在C++的標準庫里面,已經(jīng)涵蓋了很多種容器(數(shù)據(jù)結(jié)構(gòu))和算法,標準庫是很棒的團隊寫的,所以我們要善用標準庫,而不是全都自己去寫。
學(xué)習(xí)標準庫的最好方法,就是自己寫一個小程序,應(yīng)用到標準庫的每一個函數(shù),而不是只去看網(wǎng)上相關(guān)的例子(光看,不實踐)
C++11新標準
variadic template (數(shù)量不定的模板參數(shù))
上面第2函數(shù)的第二模板參數(shù)便是,用typename...(記得是在typename后面加三個點),聲明使用variadic template,表示接收一個參數(shù)包(里面有個數(shù)不定的參數(shù))
接下來,在第2函數(shù)的第二個形參,相應(yīng)的也需要的在后面,加上三個點,表示不定個數(shù)的參數(shù)包。
在調(diào)用時,也需要在參數(shù)包名稱的后面加上三個點。
例子中的第2函數(shù),會被輾轉(zhuǎn)調(diào)用,直到把42輸出是,參數(shù)包args...內(nèi)沒有參數(shù)了,print(args...)調(diào)用的就會是第1函數(shù),從而結(jié)束運行。
例子是函數(shù),當然,類也可以使用這個C++2.0的新特性。
auto
它的作用是,在變量聲明時賦值的情況下,能讓編譯器通過判斷值的類型,來確定變量的類型。
若在變量只聲明不賦值時,編譯器則無法確定變量的類型,所以最后的用法是不允許的。
ranged-base for
注釋:decl表示變量,coll表示容器
例子中,for的里面的‘{}’表示容器(它也是C++11的新標準)
例子的for語句將會實現(xiàn)的是,把容器coll里的內(nèi)容,逐個賦值給變量decl,直到容器遍歷完成。
若想要改變?nèi)萜鲀?nèi)的值,則需要使用pass by reference。
關(guān)于reference
reference在定義時一定要有初值,而且不能被改變,直到它的生命結(jié)束。
例子中,r是代表x的,r擁有x的所以特性,也就是說r和它所代表的x的大小相同,地址相同(不過這是編譯器所制造的假象)
二者不能并存的原因,是函數(shù)簽名signature相同,使程序產(chǎn)生歧義Ambiguity,導(dǎo)致編譯模棱兩可;
函數(shù)灰色部分可以加const,const也是函數(shù)簽名的一部分,所以二者其中一個加上const,就可以使它們兩者并存。