Day1
名字空間:用來限制作用域(重名問題)
Using namespace std; 全局的聲明,只有一次聲明之后使用的std中的東西就可以直接用。
::std 全局
Using myspace ::demo 使用myspace中的demo。
換行: endl \n
cin >> ival >> ch
cout << ival << ch << endl
————————————
Oop思想:面向對象的思想
屬性+行為=對象
(記憶 體會 實踐 理解 發揮)
類的聲明定義:(聲明與定義分開)
Class 聲明類
Class Demo(類名)
成員的性質(public 公共 ———— private 私有(一般數據私有) ———— protected 保護)
——————————
構造函數:不需要用戶來調用它也不能調用,而是在建立對象時自動執行
構造函數的名字必須與類名同名,而不能由用戶任意命名,以便以其系統能識別它并把它作為構造函數處理
構造函數的功能是由用戶定義的,用戶根據初始化的要求設計函數體和函數參數
如果用戶不設計,則編譯器自動生成一個默認構造函數
無返回值
普通默認構造
拷貝構造 用已有的構造新的
深拷貝和淺拷貝 默認的拷貝函數為淺拷貝,當有指針類成員時一定要自己做拷貝函數做深拷貝(使得數據區域獨立 不光是拷貝值)
Demo(const Demo & )
限制構造 類中的成員屬于私有或者保護 不允許構造
——————————
析構函數: 對象銷毀時自動調用(對于同一生命周期的成員 先構造的后析構 )
不能重載
只能用~Demo()
全局對象,進程結束時對象自動銷毀,析構自動調用
局部對象,func()調用構造,func結束析構
靜態局部對象,進程生命期,func第一次調用構造,進程結束析構
堆對象,運行時候構造,必須是delete對象才會銷毀,且自動析構,如果不delete就不析構
————————————
This 指針:
指向對象自己
Private 成員 只能在內部使用
Const 成員 不可修改
————————————
分析構造和析構的次數
——————————————————————————————————————————————————
Day3
Static :
Static 成員 (靜態成員是一種特殊成員)
不屬于任何類對象(有沒有對象都靜態成員就已經存在,且是進程生命期)
作用域在類域
靜態的,唯一的
用于限制作用域
————————————
Const :
Const 成員函數 在函數后面加const,表示該成員函數不能修改類對象(在這個函數內不能存在修改類對象的任何操作)
只要類方法不修改對象就應該聲明為const
Const 對象 const Demo obj; //只讀對象,不能被修改(obj 被定義為Demo類的只讀對象不可以被修改)
只要調用成員函數,就存在修改對象的風險,所以不能再調用成員函數。語法上不允許調用普通成員函數
Const 成員變量 const int x
只讀成員變量,那么必須使用初始化列表進行初始化
Demo::Demo(int a) : x(a) //初始化列表
只要調用x就會檢查會不會修改,x被const修飾所以不能被修改。
————————————
友元:(打破封裝可訪問類中的private protected對象)
友元的聲明可以放在類的私有部分,也可以放在公有部分,它們是沒有區別的
慎用友元,存在危險性。
友元函數 一個函數可以是多個類的友元函數,只需要在各個類中分別聲明。調用與一般函數的調用方法和原理一致
友元類 友元關系不能被繼承,是單向的,不具有傳遞性
聲明友元類時需要前項聲明(前項聲明可以不列出具體內容)
友元成員函數 存在遞歸可能 所以最好聲明定義引用分開編寫。
前項聲明不足以完全說清楚所以分開編寫。
————————————————————————————————————————————————————————————————
Day4
運算符重載:(重載——函數同名,參數不同,行為相似)
運算符重載——特殊的一種重載 (加 operator)
友元運算符重載 與函數對比,功能相同
friend const int* getaddr(const Demo &);
friend Demo& addeq(Demo &, const Demo &);
函數實現功能不直觀不容易被理解
friend const int* operator& (const Demo &);
friend Demo& operator += (Demo &, const Demo &);
運算符重載實現功能直觀便于理解
friend Demo& operator ++ (Demo &); 前++
friend Demo& operator ++ (Demo &,int);后++
——————————
成員函數運算符重載 成員函數在類中 屬于類 可以使用this 指針所以成員函數的運算符重載在傳參數時 參數個數和友元運算符重載不同。
bool operator !=(Integer &)
bool是判斷返回值(對或者錯)
【】通過數組名[]訪問數組成員,即得到一個對象
通過數組名[]訪問數組成員,即得到一個對象,
對象有一個運算符[]得到對象管理的整型數組的一個整型
arr[0]:IntArray對象
arr[0][0]:是一個整型
————————————
注意事項 除關系運算符“.”、作用域運算符“::”、sizeof運算符和三目運算符“:?”外,C++中的所有運算符都可以重載(其中“=”和“&”不必用戶重載)
重載運算符限制限制在C++語言中已經有的運算范圍內的允許重載的運算符之中,不能創建新的運算符。
運算符重載的實質就是函數重載,遵循函數重載的選擇原則
重載之后的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及語法結構
運算符重載不能改變該運算符用于內部類型的對象的含義
運算符重載是針對新類型數據的實際需要對原有運算符進行的適當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符
重載運算符的函數不能有默認參數,否則就改變了運算符的參數個數
重載的運算符只能是用戶自定義類型,否則就不是重載而是改變了現有的C++標準數據類型的運算符的規則
運算符重載可以通過成員函數的形式,也可以通過友元函數的形式,和非成員的普通函數
————————————————————————————————————————————————————
Day 5
模板:模板是對一種對類型進行參數化的工具。
模板的聲明或者定義只能在全局,命名空間或者類范圍內進行。即不能在局部范圍,函數內進行。
函數模板 參數類型不一樣的但是功能及函數名一樣的函數
函數模板的聲明定義語法上差異不大,就像普通函數一樣使用
template
T add(T x, T y);
template
C add(C x, C y)
{
return x+y;
}
類模板 成員屬性的類型和成員函數的類不一樣但是成員屬性及函數一樣的類
template
class Demo{
public:
Demo(T1 a, T2 b);
void setx(T1 a);
static void sety(Demo &, T2 val);
T1 getx() const;
T2 gety() const;
private:
static T1 x;
T2 y;
};
友元函數模板
如果一個類是模板類,又要實現運算符重載,就是一個友元函數模板;
實質是類模板和函數模板的綜合運用
template
class Demo{
public:
Demo(const int val);
public:
T getval() const;
void setval(const int val);
template
friend Demo
private:
T ival;
};
非類型模板參數
template
class Array{
public:
Array();
Array(const Array &);
~Array();
public:
T& at(const int id=0) const;
T& operator[](const int id)const;
private:
T* const buffer;
};
T:模板類型參數;len:模板非類型參數;T、len都可以有默認值
————————————————————————————————————————————
Day 6
繼承: 就是在一個已存在的類的基礎上建立一個新的類。已存在的類(學生)稱為“基類”(或父類),新建立的類(小學生)稱為“派生類”(或子類)
1.派生類繼承了基類的所有數據成員和成員函數(private雖然也繼承了,但是無法直接訪問),并可以對成員作必要的增加和調整。
2.一個基類可以派生出多個派生類,每一個派生類又可以作為基類再派生出新的派生類,因此基類和派生類是相對而言的。
3.派生類是基類的具體化,而基類則是派生類的抽象。
繼承權限 :
1.public:公有繼承。
a.公有成員變成派生類的公有成員。 b.保護成員變成派生類的保護成員。 c.私有成員:只能通過基類接口訪問。
2.protected:保護繼承。
a.公有成員,保護成員都變成派生類的保護成員 b.私有成員:只能通過基類接口訪問。
3.private:私有繼承。
a.公有成員,保護成員都變成派生類的私有成員 b.私有成員:只能通過基類接口訪問。
子類的構造析構:
順序——構造:先基類、再派生;析構:先派生、再基類
(因為派生類的構造和析構 可能會用到基累的成員,所以派生的構造在基類后,派生的析構在基類前)
Is-a
什么是a (香蕉是水果 水果為a是基類 )
Has-a
什么有a
(思想要理解 咋實踐中深入)
多重繼承:
class <派生類名> : <繼承方式1> <基類名1>,<繼承方式2><基類名2>……
使用需要注意 容易引起歧義
————————————————————————————————————————————————————————————————
Day 7
多態:多種狀態(一個接口, 多種方法) 程序運行時才決定調用的函數,是面向對象編程領域的核心概念。
多態是將接口和實現進行分離,(實現以共同的方法,但因為個體差異,而采用不同的策略)
多態的應用場景
如果基類實現不是我們想要的方法,那么在子類派生時,重寫一個新的版本
這樣其他成員函數不可以直接復用,這樣的情況就需要虛函數,即多態
虛函數 子類和基類有相同的方法,但是行為卻有所不同(多態)
(is-a 的關系不是多態,函數重載(函數行為相似)也不是多態)
用virtual修飾成員函數(虛函數)
1. 非類的成員函數不能定義為虛函數
2. 類的靜態成員函數不能定義為虛函數
3. 構造函數不能定義為虛函數,(析構可以定義為虛函數)
4. 只需要在聲明函數的類體中使用關鍵字virtual將函數聲明為虛函數,而定義函數時不需要再使用關鍵字virtual
5. 當將基類中的某一成員函數聲明為函數后,派生類中的同名函數(函數名相同,參數列表完全一致,返回值類型相關)自動成為虛函數
抽象類 隱藏類的其他成員的方法。
1. 含有純虛函數的類就是抽象類
2. 抽象類沒有完整的信息,只能是派生的基類
3. 抽象類不能有實例,不能有靜態成員
4. 派生類應該實現抽象類的所有方法
5. 抽象類不能定義對象,因為其純虛函數只有聲明沒有定義
6. 抽象類被使用只能派生,且只有有子類對象
虛析構 由于指針指向的對象是基類類型,所以delete銷毀對象的時候,并不會調用派生類的析構函數,這樣級造成了對象銷毀不完整。
工程原則:只要該類要被繼承,則析構必須是虛函數
構造函數不能為虛,析構函數一定為虛
virtual ~Base() const = 0 純虛析構函數
虛繼承 解決從不同途徑繼承來的同名的數據成員在內存中有不同的拷貝造成數據不一致的問題,將共同基類設置為虛基類。
從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝,同一個函數名也只有一個映射。
typeid(this).name() 類名
聯編(鏈接) 將模板或者函數合并在一起生成可執行代碼的處理過程。
靜態聯編(靜態鏈接) 在編譯階段就將函數實現和函數調用聯起來(早綁定)
動態聯編(動態鏈接) 在程序執行的時候才將函數實現和函數調用關聯(晚綁定)——引入一個虛函數表實現
C++中一般情況下的聯編指靜態聯編,一旦涉及到多態和虛擬函數就必須使用動態聯編
重載只是一種語言特性,編譯器根據函數不同的參數表,把同名函數區分開來屬于靜態聯編,與多態無關。
—————————————————————————————————————————————————————————
Day 8
異常: 讓一個函數在發現了自己無法處理的錯誤時拋出(throw)一個異常,然后他的(直接或間接)調用者能夠處理這個問題。
異常處理機制是一種比較有效的處理系統運行時錯誤的方法。
在執行程序發生異常時,可以不在本函數中處理,而是拋出一個錯誤信息,把它傳遞給上一級的函數來解決,上一級解決不了再傳遞給上一級,一直直到最高一層還無法處理的話,運行系統會自動調用系統函數terminate,由他調用abort終止程序。
異常處理——try(檢查)——》throw(拋出)——》catch(捕獲)
自定義異常 設計程序時會自定義很多錯誤,這些錯誤在標準錯誤里是沒有的,所以我們往往需要自定義很多異常類。
自定義異常可以從標準異常exception類派生出來 也可以完全自定義一個異常類。
在定義的異常函數后必須加上空異常的關鍵字——因為異常函數自身需要嚴格定義不允許異常函數有異常報出。(通用 throw() 空異常 高版本用 nothrow關鍵字)
轉換函數:
Int val = 0;
Char ch = ‘a’;
Int main (int argc, char *argv[])
{
Val = ch; //隱式轉換
Ch = char(val) // 顯式轉換
}
轉換函數的實質為運算符重載,只是重載的運算符不是內置的運算符而是類
Operator 類型名()
{
實現轉換的語句
}
規則——轉換函數只能是成員函數,無返回值,空參數
不能定義為void的轉換,也不允許轉換成數組或者函數類型
轉換常定義為const形式,(轉換函數并不改變數據成員的值)
Explicit關鍵字—— 修飾類的構造函數,被修飾的構造函數的類,不能發生相應的隱式類型轉換
給單參數的構造函數使用explicit關鍵字,阻止可能產生的隱式轉換:由成員變量類型轉換為類類型