-
名稱空間std封裝的是標準庫的名稱,標準程式庫爲了和以前的標頭檔案區別,一般不加 .h;
-
C C++ 區別
- C語言中只有一個全域性作用域;所有的全域性識別符號共用一個作用域;
- C++變數檢測增強,不允許定義多個同名的全域性變數;C++對於struct一組變數的集合,c++認爲是一個新型別的定義說明;
- int fun( ); c語言中可以接受任意參數的函數;C++中表示無參函數;
- C++中新增bool型別;
-
C++ 中const修飾的,是一個真正的常數,而不是c中的只讀變數,有自己的儲存空間;
- C++中爲全域性變數且在其他檔案中使用,或使用&取const常數地址時,會分配儲存空間,const修飾參照時,也會分配儲存空間;
-
參照:
- 參照在C++的內部實現是一個常數指針;Thttps://blog.csdn.net/baidu_34170531/article/details/ype& name 等價於Thttps://blog.csdn.net/baidu_34170531/article/details/ype* const name;
- 參照所佔用的記憶體空間與指針保持一致;在64位元系統中佔用8個位元組;
- 參照,指針,複製;
- 當函數的返回值爲參照時,若返回棧區變數,不能成爲其他參照的初始值,不能作爲左值使用;若返回靜態變數或全域性變數,可以成爲其他參照的初始值,既可以作爲右值使用,可以作爲左值使用;
- 被呼叫函數作爲左值時,必須返回一個參照;const Thttps://blog.csdn.net/baidu_34170531/article/details/ype& name = var;讓變數擁有隻讀屬性;
-
函數的擴充套件:
- C++中的const常數替代宏常數定義;使用inline宣告的行內函式替代宏程式碼片段;宏程式碼片段有前處理器處理,進行簡單地文字替換,沒有任何編譯過程;
- inline只是一種請求,編譯器不一定響應;行內函式省去了普通函數呼叫時的壓棧、跳轉和返回的開銷;
- 預設參數和函數的佔位參數結合可以爲以後的程式擴充套件留下空間,相容C程式;
- 函數過載:同一個函數名搭配不同的函數參數;參數個數/參數型別/參數順序三者其一,注意過載中的預設參數,發生在一個類中;
-
struct定義類,所有成員的預設屬性是public;class的預設屬性是private;
-
C++ 編譯器提供的預設cophttps://blog.csdn.net/baidu_34170531/article/details/y建構函式、等號操作均屬於淺拷貝;
-
類
- 成員變數的初始化順序與宣告的順序相關,與在初始化列表中的順序無關;
- 建構函式:當類中成員變數是其他類的物件時,首先呼叫成員變數的建構函式,呼叫順序與宣告順序相同,之後呼叫自身型別的建構函式;解構函式(destructor)呼叫順序與對應的建構函式相反;
-
物件的動態建立與釋放:
- new delete : 用 new 分配陣列空間時,不能夠指定初始值;且應該判斷返回值是否是空指針;
- Box *pt=new Box(12,15,18); new時可以直接對新建立的物件進行初始化;new申請堆空間未必成功,應判斷返回值;
- malloc不會呼叫類別建構函式, Free不會呼叫類的解構函式;
- static靜態成員變數由多個物件共用,區域性於類,不是物件成員;
- 靜態成員函數提供不依賴類數據結構的共同操作,沒有this指針;呼叫:使用 類名:: 作限定詞或通過物件呼叫;不能呼叫普通成員變數;
-
物件導向模型:
- 成員變數:普通成員變數 儲存在物件中;靜態成員變數儲存在全域性數據區中;
- 當類中含有static成員變數時,該變數是儲存在靜態區當中的,它是一個共用的量,因此,在類建立一個範例物件的時候,是無需再爲static成員變數分配空間的,sizeof(物件)的大小排除靜態成員變數;
- 成員函數儲存在程式碼段;
- C++中的普通成員函數 都隱式包含一個指向當前物件的this指針;靜態成員函數不包含指向具體物件的指針;
-
友元
- 若類B是類A的友元類,則B類中的所有成員函數均是類A的友元函數;
- 友元類通常設計爲一種對數據操作或類之間傳遞訊息的輔助類;
-
運算子過載
- 函數過載:一個函數名可以代表不同功能的函數;對一個已有函數賦予新的含義;
- 運算子過載的本質是一個函數;不能夠進行過載的運算子: . :: .* ?: sizeof
- 可以對運算子做出新的解釋;但不改變運算子的優先順序、結合性、所需要的運算元,不建立新的運算子;
- 運算子過載只是定義了相對於一個特定類的新運算子,原有意義沒有失去;
- 運算子過載的兩種方法: //全域性什麼的看不懂;
- 運算子函數可以過載爲 成員函數 或是 友元函數 ,區別在於成員函數有 this指針,而友元函數沒有;但兩者的使用方法相同;-- 但是傳參的方法不同,實現程式碼不同,使用場合不同;
- 在參數需要隱式轉換的情況下,使用友元函數 過載運算子是正確的的決定;
- 陣列下標運算子[]
- 是 二元運算子;
- 只能用於 成員函數過載,不能用於友元函數過載;
- x[https://blog.csdn.net/baidu_34170531/article/details/y] 可以理解爲: x.operator
- x ( arg1, arg2, … ) 可以理解成: x . operator () (arg1, arg2, … )
- 以上兩式 x 爲物件;
看到5 沒看完 P92
-
繼承和派生
- C++的 繼承方式(public、private、protected) 會影響子類的對外存取屬性;
- 繼承
- 子類 擁有父類別的所有成員變數和成員函數;
- 子類可以擁有父類別 沒有的屬性和方法;
- 子類物件 可以當做 父類別物件使用;
- 派生
- 存取控制
- 派生類 繼承了 除了構造和解構成員方法 之外的基礎類別的全部成員函數及成員方法;
- 這些成員的存取屬性,可在派生的過程中調整;
- 繼承方式改變繼承成員的存取屬性:
- public繼承: 所有父類別成員在子類中保持原有的 存取級別;
- private繼承: 所有父類別成員在子類中變成 private成員;
- protected繼承: 父類別中,public 變 protected;
protected 仍是 protected;
private 仍是 private;
- private成員: 在子類中仍然存在,但卻無法存取;
- 無論哪種方式繼承 基礎類別, 派生類都不能直接使用基礎類別的私有成員;
- public、protected、private 的存取級別:
- public: 能夠被外界存取的成員;
- protected: 當前類和子類中 被存取;
- private: 只能在當前類中被存取;
- 繼承中的 構造和解構
- 公有派生類 具備了基礎類別的所有功能,在需要基礎類別物件的任何地方,都可以使用 公有派生類的物件進行替代;
- 子類就是特殊的父類別;
- 繼承中的物件模型
- 類 在C++編譯器的內部可以理解爲結構體;
- 子類 是由父類別成員疊加子類新成員得到的;
- – 基礎類別、派生類 – 父類別、子類
- 繼承中的構造 & 解構
- 子類物件構造時,需要呼叫 父類別建構函式 對繼承來的成員進行初始化;
- 子類物件解構時,需要呼叫 父類別解構函式 清理繼承來的成員;
- 繼承中的 構造解構呼叫原則:
- 子類物件 在建立時會首先呼叫父類別的建構函式;
- 當父類別的建構函式執行結束後,執行子類別建構函式;
- 當父類別的建構函式有參數時,需要在子類的初始化列表中 顯式呼叫;
- 解構函式呼叫的先後順序 與建構函式相反;
- 呼叫順序: 繼承與組合混合搭配的情況下:
- 先構造父類別,再構造成員變數,最後構造自己的; //依次序多重繼承時,先構造第一父類別,依次繼承構造;
- 先解構自己,再解構成員變數,最後解構父類別; //與構造順序 相反;
- 先構造的物件,後釋放;
- 繼承中同名成員變數 處理方法:
- 子類成員變數 與 父類別成員變數 同名時,子類從父類別中繼承同名成員;
- 使用作用域 :: 進行同名成員的區分;-- 在派生類中使用基礎類別的同名成員,要顯式使用 類名限定符::
// d.base::b = 2; – d derived 派生類;
- 同名成員儲存在 記憶體的不同位置;
- 基礎類別成員 的作用域延伸到所有派生類;
- 派生類的重名成員 遮蔽基礎類別的同名成員; 遮蔽基礎類別的同名成員函數,呼叫自身的成員函數;
- 派生類中的static 關鍵字:
- 基礎類別定義的靜態成員,將被所有派生類共用;
- 派生類中存取靜態成員: 類名::成員 或是 物件名.成員
- static 存取
- 也遵守:3個存取原則: private protected public
- 派生類 對基礎類別成員的存取 由繼承方式和成員性質決定;
- 不但要初始化,更重要的 顯式高速編譯器分配記憶體;
- 建構函式預設private;
-
多繼承
- 一個類 有多個直接基礎類別的幾個關係: --直接繼承自多個基礎類別;
- 虛繼承:
- 一個派生類從多個基礎類別派生,而這些基礎類別又有共同的基礎類別:則在對該類宣告的名字進行存取時,可能產生二義性; 使用上層基礎類別::x 存取上上層基礎類別的成員; --P117
- 使公共基礎類別在派生類中只產生一個子物件,必須將該基礎類別宣告爲 虛繼承; 使公共基礎類別成爲虛基礎類別;
- 虛基礎類別 宣告使用關鍵字 virtual; ---- 再看 P119 圖片分析;
-
多型
-
概述:
- 父類別中被重寫的函數依然會繼承給子類; 預設情況下,子類中重寫的函數將隱藏父類別中的函數;
- 通過 作用域符號:: 可以存取父類別中的被隱藏的函數; – 多型 看不懂了;
- 多型: 同樣的呼叫語句 有不同的表現形態;
根據實際的物件型別決定函數呼叫語句的具體呼叫目標;
- 父類別和子類指針的步長不同,不要用父類別指針++ 方式運算元組;
-
多型 實現
- C++通過virtual關鍵字對多型進行支援;
- 使用 virtual 宣告的函數被重寫後可以展現出多型特性;
-
多型成立的3個條件:
- 要有繼承;
- 要有函數重寫;
- 要有父類別指針(父類別參照)指向子類物件;
– 根據指針所指向的實際物件型別 來判斷如何呼叫;
// 多型時設計模式的基礎,是框架的基礎;
-
理論基礎
- 靜態聯編 動態聯編
- 聯編: 一個程式模組、程式碼之間互相關聯的過程;
- 靜態聯編: 程式的匹配、連線在便已經階段完成; --過載函數使用靜態聯編;
- 動態聯編:程式聯編推遲到執行時進行(遲系結); --switch、if語句是動態聯編;
-
函數過載 & 函數重寫
- 函數過載
- 必須發生在同一個類中;
- 子類無法過載父類別的函數,父類同名函數將被覆蓋;
- 過載是在 編譯期間 根據參數型別和個數決定函數呼叫;
- 函數重寫
- 必須發生在 父類別和子類 之間;
- 並且父類別與子類中的函數必須具有完全相同的原型;
- 使用 virtual 宣告之後能夠產生多型,(如果不使用virtua,叫重定義)
- = 多型是在執行期間根據 具體物件的型別決定函數呼叫;
-
派生類的 解構函式
- 解構 由基礎類別指針建立的派生類物件 沒有呼叫派生類的解構函式;
- 解構 由派生類指針建立的派生類物件 正確使用派生類解構函式;
-
多型原理探究
- 理論
- 虛擬函式表的指針 (vptr)
- 多型的實現原理
- 類中 宣告虛擬函式時,編譯器會在類中生成一個虛擬函式表;
- 虛擬函式表是一個儲存類成員指針的數據結構;
- 虛擬函式 是有編譯器自動生成與維護的;
- virtual成員函數會被編譯器放入到虛擬函式表中;
- 存在虛擬函式時,每個物件都有一個指向虛擬函式表的指針; --vptr指針
- 編譯器確定 函數是否是虛擬函式
- 不是虛擬函式,編譯器可直接確定被呼叫的函數; --靜態編譯;
- 是虛擬函式,根據物件的vptr指針,在所指的虛擬函式表中查詢fun()函數,並呼叫;
– 查詢和呼叫 在執行時完成(實現所謂的動態編譯)
與普通函數相比,虛擬函式的效率要低很多;
子類物件構造時,在父類別的建構函式中呼叫虛擬函式,產生不了多型;
-
純虛擬函式和抽象類
- 基本概念
- 純虛擬函式: 是一個在基礎類別中說明的虛擬函式,在基礎類別中沒有定義,要求 任何派生類都定義自己的版本;
- 純虛擬函式爲各派生類提供了一個公共介面(介面的封裝和設計、軟體的模組功能劃分);
- 說明式: virtual 型別 函數名(參數表) = 0;
- 一個具有純虛擬函式的基礎類別 稱爲抽象類;
- 抽象類
- 抽象類不能建立物件; ???
- 抽象類不能作爲返回型別;
- 抽象類不能作爲參數型別;
- 可以宣告抽象類的參照; 可以宣告抽象類的指針;
- 抽象類在多繼承中的應用:
- 抽象類 可以模擬java的介面類;
- 多繼承帶來的程式碼複雜性遠勝於其帶來的便利;
- 在設計方法上,任何多繼承都可以用單繼承代替;
- C++中使用純虛擬函式 實現介面;絕大多數物件導向的語言都不支援多繼承;
- 多繼承應用場景
- 介面類只有函數原型定義,沒有任何數據的定義;
- 介面類 只是一個功能說明,而不是功能實現; 子類需要根據功能說明定義功能實現;