一、虛函數表
什麼是虛函數表,在C++的類中,一旦成員函數中有虛函數,這個類中就會多一個虛函數表指針,這個指針指向一個虛函數表,表中記錄了這個類中所有的虛函數,當這個類被繼承,它的子類中也會有一個虛函數表(不管子類中有沒有虛函數),如果子類的成員函數中有函數簽名與父類的虛函數一樣的就會用子類中的函數替換它在虛函數中的位置,這樣就達到了覆蓋的效果
當通過類指針或引用調用函數時,會根據對象中實際的虛函數表記錄來調用函數,這樣就達到了多態的效果
二、虛析構
當使用 delete 釋放父類指針時,不管實際指向的對象是子類還是父類都會調用父類的析構函數(多態肯定會出現的問題)
如果子類的析構函數有需要負責釋放的內存,就會造成內存泄露
爲了解決這個問題,可以把父類的析構函數設置爲虛函數,析構函數進行覆蓋時不會比較函數名。
當父類的析構爲虛函數時,通過父類指針或引用釋放子類對象時,會自動調用子類的析構函數,子類的析構函數執行完成後也會調用父類的析構函數。
注意:析構函數可以是虛函數,但構造函數不可以。
三、強制類型轉換
注意:C++中爲了兼容C原因,(目標類型)源類型 依然可以使用,但C語言中的強制類型轉換安全性差,因此建議使用C++中的強制類型轉換
注意:C++之父認爲如果代碼設計的完善,根本不需要用到強制類型轉換,而C++的強制類型轉換之所以設計的很複雜,是爲了讓程序員多關注代碼本身的設計,儘量少使用。
C++中的強制類型轉換保證沒有很大的安全隱患
static_cast <目標類型>(源類型)
編譯器會對源類型和目標類型做兼容性檢查
dynamic_cast<目標類型>(源類型)
編譯器會會對源類型和目標類是否同爲指針或引用,並且存在多態型的繼承關係
const_cast<目標類型>(源類型)
編譯器會會對源類型和目標類是否同爲指針或引用,除了常屬性外其他必須完全相同否則報錯
reinterpret_cast<目標類型>(源類型)
編譯器會會對源類型和目標類是否同爲指針和整數進行檢查
靜態編譯:
指針或引用的目標是確定的,在編譯時期就經過了所有類型檢查、函數調用
動態編譯:
指針或引用的目標是確定(多態),只有函數調用時候才確定,具體是哪個子類。
四、I/O流
ios::in 以讀權限打開文件,不存在則失敗,存在不清空
ios::out 以寫權限打開文件,不存在則創建,存在則清空
ios::app 打開文件用於追加,不存在則創建,存在不清空
ios::binary 以二進制模式進行讀寫
ios::ate 打開時定位到文件末尾
ios::trunc 打開文件後清空
fstream/ifstream/ofstream類用於進行文件操作
構造函數或成員函數 open 用於打開文件
good成員函數檢查流是否可用
eof成員函數用於輸入流是否結束
>>操作符用於從文件中讀取數據到變量
<<操作符用於輸入數據到文件
IO流有一系列格式化控制函數,類似於左對齊、右對齊、寬度、填充、小數點位數
二進制讀寫:read/write
read(char_type *__s,streamsize __n);
gcount成員函數可以獲取上次流的二進制讀寫操作的字節數
write(char_type *__s,streamsize __n);
good成員函數可以獲取到寫t操作是否成功
隨機讀寫:seekp (off_type,ios_base::seekdir)
功能:設置文件的位置指針
off_type:偏移值
正值向右,負值向左
seekdir:基礎位置
ios::beg 文件開頭
ios::cur 文件當前位置
ios::end 文件末尾
獲取文件
該成員函數返回當前文件流的位置指針(字節數)
也可以藉助此函數獲取文件的大小
fs.tellp() 返回字節數
練習:使用C++標準IO實現帶覆蓋監測的cp命令
五、類型信息 typeid
用於獲取數據的類型信息
name成員函數,可以獲取類型的名字,內建類型名字使用縮寫
同時還支持 == != 用來比較是否是同一種類型
如果用於判斷父子類的指針或引用,它不能準確判斷出實際的對象類型
但可以判斷出具有多態繼承的關係的父子類的指針或引用,它的實際類對象。
sudo find / -name filename
sudo find / | grep "std"
grep 'Base' * 當前目錄查找文件中包含的字符
grep -r 'Base' * 當前目錄查找文件中包含的字符,包括所有子級目錄
grep -r 'Base' * dir 指定目錄下查找文件中包含字符,包括所有子級目錄
六、異常處理
拋異常
throw 數據
拋異常對象
拋基本類型
注意:不能拋出局部對象的指針和引用
注意:如果異常沒有被捕獲,程序就會停止
捕獲異常
try{
可以拋出異常的代碼
}
catch(類型 變量名) // 根據數據類型進行捕獲
{
處理異常,如果無法處理可以繼續拋出異常
}
注意:捕獲異常的順序是自上而下的,而不是精準的匹配,針對子類異常捕獲時要放在父類的前面
函數的異常聲明:
返回值類型 函數名(參數列表)異常聲明
注意:如果不寫異常聲明表示什麼類型的異常都可能拋出
注意:如果寫了異常聲明表示只拋出某些類型的異常,一旦超出異常聲明的範圍,程序會直接結束,無法捕獲
注意:threw()
設計異常類:
class Error
{
int errno;
char errmsg[255];
public:
Error(int errno = -1,const char* msg = "未知錯誤")
{
this->errno = errno;
strcpy(errmsg,msg);
}
int getError(void);
{
return errno;
}
const char* getErrmsg(void)
{
return errmsg;
}
};