1.轉換函數
在執行Fraction f(3,5)時,使用到了重載的操作符(),這樣就將f轉化為0.6。
在使用轉化函數時應當注意以下幾點:
(1)轉換函數是不能有參數的;
(2)轉換函數是不需要指定返回類型的,編譯器將自動賦予其返回值類型;
(3)在一個類中可以有多個轉換函數。
在上圖中,沒有重載操作符(),而是對操作符+做了重載。在其中使用了Fraction& f。Fraction類的構造函數是一個non-explicit-one-argument ctor (無explicit 的單實參構造函數)。由于存在默認參數值,所以此構造函數實際上只需要一個參數就行。
在使用代碼段中,沒有將f(3,5)轉換為0.6,因為在類中未對()操作符進行重載,而在執行+操作時使用了重載的+操作符,因而將4轉化為4/1。
此過程可以看成是第一類轉換函數的逆過程。
那么如果兩者都被使用時,那么就會出現二義性。是將f(3,5)轉換為0.6?還是將4轉換為Fraction(4,1)?兩者無法確定!
為此C++提供了關鍵字:explicit。通過explict指定了轉換函數。避免出現二義性錯誤。注意:explicit應用于構造函數的前面。
2.智能指針
智能指針是由一種類類型引出的:pointer-like classes,一個類被設計得像一個指針。
智能指針的構造函數 shared_ptr (T* p):px(p){},其中必然帶著一個普通指針。指針所允許的動作,所創建出的class也要允許。例如 shared_ptr支持對*號和箭頭的重載。
迭代器也是另外一種智能指針,與此同時迭代器所要處理的操作更多,如*、箭頭、++、--等,以滿足迭代器更多功能的要求(例如對容器的遍歷等)。
3.仿函數
在C++中能夠支持()操作的對象都被稱之為function-like對象。
在上圖中三個結構體都對()操作進行了重載,一次均為仿函數。在上圖中灰色區域部分為仿函數類的父類。
應當注意:在標準庫中,仿函數所使用的奇特的base classes的理論大小為0,實際得到的可能為1。
4.namespace
namespace是為了避免出現名稱沖突。其基本結構如下:
namespace jj01{
? ? function1(){...};
}
使用時:jj01::function1();
不同的namespace的要素名稱可以相同。
5.模板
5.1 類模板
課件中的類中的復數的實部與虛部的數據類型不定,數據類型在使用時確定。
5.2函數模板
函數模板要注意實參推演。實參推導出的類型應當保證能夠支持相對應的操作。在編譯時,會編譯兩次。首次會檢查其中是否包含語法錯誤。第二次編譯則會是在模板被使用的時候,保證模板中所定義的操作能夠被正確支持。
5.3成員模板
就是講一個模板作為另一個模板的成員。
在使用成員模板時應當注意其繼承關系。
5.4模板特化
特化過程指定了特定的數據類型。
template<>struct hash
{
? ? ? ? // 重載()操作符
? ? ? ?size_t operator()(int x){return x};
}
// 使用
cout<<hash<char>()(10);
以上所述為模板的全特化,還存在模板的偏特化:
(1)個數的“偏”:對部分模板參數進行參數類型的綁定;
(2)范圍上的“偏”:例如由接受任意類型變為只接受指針。
5.5 模板模板參數
XCls<string,list>mylst1; 存放string的list,list本身就是模板,但是這是錯誤的!!因為:容器在構造時會需要多個模板參數。
6.variadic templates 數量不定的模板參數
上述代碼的過程相當于一次遞歸調用。
7.auto
在其中編譯器自動推演返回類型。應當注意:并不是所有的變量都是用auto。除非每次聲明變量都進行賦值。否則就會出錯。
8.ranged-based for
數據必須是從容器中取值(注意:{}是天然的容器)。在上述代碼中應當記住以下:
pass by value:乘以3不會影響原數據。
pass by reference:乘以3會影響原數據。
9.reference
應當注意以下幾點:
(1)int& r = x; //r代表x,r與x都是0,不是一個指針;
(2)reference必須要有初值。reference指定后就不能改變;
(3)int x2 = 5;
r = x2;// r不能再代表其他值,r此時代表的是x,所以當前r與x都是5。
reference通常不用于變量的聲明,而是常用于對參數類型和返回類型的描述。