1. C++編程簡介
2.頭文件與類的聲明
c語言的數據暴漏的太多,任何函數都能訪問,不容易維護
類分兩種,內部帶指針的和不帶指針的
類里有指針要非常小心
.h和.cpp是一部分,因為角色的區分,分成兩部分
自己的頭文件用雙引號,庫的用尖括號
可以把.h拿掉,c的stdio要寫成cstdio
3. 構造函數
private:主要作用是要封裝起來內部細節
訪問級別可以任意交錯
創建對象的時候構造函數自動被調用。不需要返回值,因為不需要自己創建本對象。初始化列表構造函數獨有。數值設定分兩階段,用初始化和賦值,先初始化再復制。初始化列表屬於初始化,構造函數體是賦值
初始化列表的使用顯得大氣上檔次
不帶指針的類,多半不用寫析構函數
重載是給函數改名
構造函數一個是有默認參數,一個是沒有參數,這樣不行,兩者沖突,因為編譯器不知道選哪個函數,結果不唯一
c1和c2()這兩種方式創建對象都可以
4.參數傳遞與返回值
函數在參數和body之間加const,代表函數不會改變對象內容
const對象調用非const方法會報錯
不改值的函數用const修飾是個好習慣
盡量不要pass by value,復制浪費時間、空間。引用像指針但是更漂亮,使用更自然。引用、指針一般更快、更省空間,但和小字節數據比還是差
按值傳遞是復制參數,改了參數也不會改原值,引用為了達到這種效果,要用const在變量類型前修飾,這樣確保不會改變實參
返回引用效率更高,返回值盡量是reference,有的情況不能返回ref
友元比用函數拿效率高點,但是打破了封裝
正規寫法:
1.數據放private
2.參數盡可能以reference來傳,根據要不要改實參決定要不要帶const
3.返回值盡量以reference來傳
4.在類本體里定義的函數,不改值的加const
5.構造函數用初始化列表初始化
返回reference:返回的是一個本來就有的東西,不會有錯。local對象就不能做為reference返回
reference主要用在傳遞東西上
5. 操作符重載與臨時對象
編譯器自動把c2地址傳進來當成this,this是函數的隱藏參數
返回的是引用,接收端怎么接收不用在乎,用引用和value接收都可以,方便書寫,只是效率有差別。傳回指針就不行了,必須用指針接收,無法連着用。如果不加引用返回一個已存在對象,相應的會生成一個臨時對象,構造、拷貝、析構分別來一次(造一個對象,要不用來常量引用要不用來拷貝,對左值修改影響不了原值,引用直接編譯報錯;NRVO可以優化不生成對象,直接走拷貝,效率一致,但NRVO可能失效),引用則是指針賦值或者拷貝一次。返回臨時對象少復制一次只有一次構造,有編譯器優化(RVO)
重載只有一個能符合,多了編譯器報錯
多個參數,順序不定,用全局的容易掌控
參數沒有this pointer
臨時對象,沒有名字,聲明在下一行已經結束了
運算符 全局重載,靠參數個數確定函數名.只有一個參數放對象左邊的,可以設計為全局函數也可以設計為類函數,運算符重載函數的結合性和默認的是一樣的
有些類不能修改,要用全局運算符重載其運算符
不是自己寫的,參數別加const
6.復習Complex類的實現過程
7. 三大函數:拷貝構造,拷貝復制,析構
拷貝構造與拷貝賦值區別:一個是構造初始化一個是賦值,拷貝構造的對象之前不存在,所以與賦值構造處理不同,不用清理以前的垃圾
默認的是按bit復制,沒有指針、引用就夠用
s1()也會調用構造函數
淺拷貝,內存泄漏和數據別名
拷貝構造函數只是復制,不想改變外面對象,所以要const參數
判斷是否是自己,清空已有數據,拷貝新數據。給已有對象重新賦值
沒有自我賦值檢測,一是慢,二是產生懸垂指針
8,堆、棧與內存管理
對象的內存,要不位於棧區要不位於堆區
析構函數自動被調用
global對象構造函數早在main執行前就被調用
類中的靜態變量與全局變量相同。它的構造函數將在進入 main 函數之前被調用。
- 結論(適用於 g++、Windows 環境):
- 全局變量 和 類中的靜態成員 : 在輸入之前調用構造函數 主 功能 (1) .
- 局部靜態變量 : 構造函數僅在第一次執行到達其聲明時調用。
- 如 局部靜態變量為 POD 類型 , 那么在輸入 之前也是初始化的主 功能 (1) .
POD 類型示例:static int number = 10;
(1) :正確的狀態應該是:“在調用來自同一翻譯單元的任何函數之前”。但是,為了簡單,如下例所示,它是主要功能。
內存泄漏:沒機會再delete堆上對象了,失去了控制
"operator new",函數名就叫這個
刪除兩塊堆上的內存
上下紅色cookie用於記錄整塊大小,方便回收
最后一位,0x41, 1用來表示已分配不可用,0用來表示可用未分配。最后一位可以借位是因為地址一定是16的倍數,所以最后一位必為零
數組個數排在數據前面
這里指針對象、數組指針還是指向對象內存地址的,而不是cookie等附加數據,相應的delete函數會自己去找
寫不寫中括號不影響內存刪除,但是影響析構函數調用,內存泄漏的是數據里的指針指向的堆內存。如果是復數類而不是字符串,加不加中括號都行
9. 復習String類的實現過程
10. 擴展補充:類模板,函數模板,及其他
靜態成員數據是類只有一份,靜態函數只能操作靜態對象成員
靜態成員數據要在類外面初始化,不然編不過。
這也叫靜態成員的定義,定義會開內存空間。類里面的是聲明而已,因為靜態成員脫離於對象,是屬於類的
懶漢與餓漢模式區別
template里typename和class相通
類模板明確指出type,函數模板是根據參數自行推導
namespace解決同名問題
11. 組合與繼承
面向對象編程:類和類之間產生關系
黑色菱形代表里面有東西
編譯器幫助調用部件的構造、析構。
各自管各自的構造和析構即可,編譯器全做好了
如果調用默認的構造、析構不合適,就自己在初始化列表上調用組件的構造函數
白色菱形是委托,用指針指向,有些虛
二者壽命不一致
pImpl模式:左邊是接口,真正的實現在委托那里,方便實現變動、切換,這樣就具有了彈性
這種手法也叫做編譯防火牆
還有就是cow技術,改的時候才真正開辟新內存進行拷貝,不然就是復制一個指針
白色三角形代表繼承
基類析構不是virtual,可能發生只調用基類析構不調用子類析構
12. 虛函數與多態
繼承主要作用是要搭配虛函數,內存布局倒是其次
函數的繼承不應該從內存的角度理解,函數的繼承繼承的是調用權
子類可以調用父類的函數
形狀很抽象,沒什么東西就直接是形狀,所以要定義有純虛函數
虛函數:希望子類來做,父類不做或者做的默認實現比較簡單
關鍵動作延緩到子類去做,叫做template method
本質是虛函數通過vptr來調用,看是this指針是哪個對象就調到哪個函數
既有基類又有Component,先調用基類構造函數
13. 委托相關設計
組合模式:容器可以容納單體及容器
C++容器里要放指針,因為必須一樣大小,放對象可能基類、子類不一樣大
原型模式:應對未來之對象,要求其繼承已有對象,用靜態對象創建自己,構造函數里將其add進框架,框架提供虛函數,子類實現copy子類自己創造的東西
LSAT:帶下划線,是靜態的,所以類自己創造了自己
類圖先寫名字再寫類型
-代表private,#代表protected
通過存儲的指針調用相應類的clone方法,clone里調用protected構造函數防止調用私有的構造函數又注冊一次
框架應有之意:實現框架預置的方法,框架先寫好了又要讓他知道自己