怎么與其他網(wǎng)站做友情鏈接免費收錄網(wǎng)站
文章目錄
- 異常
- 概念:
- **拋出異常:**
- 關(guān)鍵字:
- **捕獲異常:**
- **棧解旋:**
- **異常的接口聲明:**
- **異常對象的生命周期:**
- 1 傳遞異常對象
- 【不使用】
- 2 傳遞異常對象指針
- 【不使用】
- 3 傳遞異常對象引用
- 【**最優(yōu)解**】
- **異常的多態(tài):**
- 標準異常庫:
- 自定義異常類:【了解】
- 最需注意的點:
- 拷貝構(gòu)造
- 析構(gòu)函數(shù)
- 必須手動回收
- 野指針與空指針
- 虛函數(shù)與純虛函數(shù)
- 虛析構(gòu)造與純虛析構(gòu)
- 類模版
異常
概念:
程序中因硬件或代碼編寫時考慮不足導(dǎo)致的程序崩潰
硬件問題: 不予處理
代碼編寫考慮不足: 要處理
? 分類:
- 編譯時錯誤: 語法錯誤導(dǎo)致
運行時錯誤: 考慮不足導(dǎo)致
拋出異常:
關(guān)鍵字:
throw : 拋出
語法:
throw 數(shù) 據(jù);
捕獲異常:
語法:
try {} catch(數(shù)據(jù)類型1 變量名1) {} catch(數(shù)據(jù)類型2 變量名2) {} ......
示例:
#include <iostream> using namespace std; void myDiv(int n01, int n02) {//什么情況下拋出異常if (n02 == 0){// throw 1;throw 'a'; // 這里拋出的 就是catch 接收的值} } int main(int argc, char const *argv[]) {try{cout << "1111" << endl;myDiv(10, 0);cout << "222" << endl;}catch (int e){cout << "int 除0了" << endl;}catch (char e){cout << "char 除0了" << endl;}return 0; }
注意:
> 如果在try中出現(xiàn)異常,其try中剩余代碼將不在執(zhí)行,進入對應(yīng)的catch中
> catch中變量的值就是拋出異常時throw后的數(shù)據(jù)
> catch可以有多個
棧解旋:
只能解旋棧區(qū)的東西 堆區(qū)的沒戲 new的 都得自己去釋放
概念:
> 當try中出現(xiàn)異常,其異常代碼之上創(chuàng)建的對象都會被釋放 > 其釋放順序與創(chuàng)建順序相反 > 這種情況稱為棧解旋注意:new創(chuàng)建的對象在堆區(qū),無法自動釋放
#include <iostream>
using namespace std;
class Data
{
public:Data() {cout << "構(gòu)造函數(shù)" << endl; }~Data() { cout << "析構(gòu)函數(shù)" << endl; }
};
class Data02
{public:Data02() { cout << " Data02 構(gòu)造函數(shù)" << endl; }~Data02() { cout << " Data02 析構(gòu)函數(shù)" << endl; }
};
int main(int argc, char const *argv[])
{try{//Data *d01 = new Data();//Data02 *d02 = new Data02();Data02 d02;Data d01;throw 1;}catch (int e){cout << "xxxx" << endl;}return 0;
}
異常的接口聲明:
語法:
返回值類型 函數(shù)名(形參列表) throw (可能拋出的異常1 , 可能拋出的異常2 ,...) {函數(shù)體; }
注意:
如果 throw() 就是里面沒東西
說明當前函數(shù)沒用異常
throw() == noexcept 沒有異常
// 異常的接口聲明 #include <iostream> using namespace std; // 此時在VSCode會顯示紅色,但是語法沒有問題 void myDiv(int x, int y) throw(int, char) {if (y == 0){throw 1;}cout << x / y << endl; } int main(int argc, char const *argv[]) {try{myDiv(10, 0);}catch (int e){}catch (char e){}return 0; }
異常對象的生命周期:
1 傳遞異常對象
【不使用】
缺點: 占用內(nèi)存大
此時會觸發(fā)拷貝構(gòu)造,會形成一個新的異常對象,就得銷毀這兩個對象
示例:
#include <iostream> using namespace std; class MyException { public:MyException(){cout << "構(gòu)造函數(shù)被調(diào)用" << endl;}MyException(const MyException &e){cout << "拷貝構(gòu)造被調(diào)用" << endl;}~MyException(){cout << "析構(gòu)函數(shù)被調(diào)用" << endl;} }; int main(int argc, char const *argv[]) {try{// MyException():創(chuàng)建了MyException的一個對象,該對象沒有對象名,稱為匿名對象throw MyException();}catch (MyException e){}return 0; }
2 傳遞異常對象指針
【不使用】
缺點:會造成內(nèi)存泄漏
傳遞異常對象,創(chuàng)建一次 但是不銷毀 因為沒delete
#include <iostream> using namespace std; class MyException { public:MyException(){cout << "構(gòu)造函數(shù)被調(diào)用" << endl;}MyException(const MyException &e){cout << "拷貝構(gòu)造被調(diào)用" << endl;}~MyException(){cout << "析構(gòu)函數(shù)被調(diào)用" << endl;} }; int main(int argc, char const *argv[]) {try{// 傳遞的是指針throw new MyException();}catch (MyException *e){}return 0; }
3 傳遞異常對象引用
【最優(yōu)解】
傳遞異常對象引用,只會創(chuàng)建一次,而且可以自動銷毀
示例:
#include <iostream> using namespace std; class MyException { public:MyException(){cout << "構(gòu)造函數(shù)被調(diào)用" << endl;}MyException(const MyException &e){cout << "拷貝構(gòu)造被調(diào)用" << endl;}~MyException(){cout << "析構(gòu)函數(shù)被調(diào)用" << endl;} }; int main(int argc, char const *argv[]) {try{// 傳遞的是異常對象的引用throw MyException();}catch (MyException &e){}return 0; }
異常的多態(tài):
注意:
1 拋出的子類異常,可以被父類異常類型接收 2 拋出的子類異常,catch 中 有父類異常與子類異常類型,此時按代碼順序書寫接收,建議先子后父
示例
#include <iostream> // 異常的多態(tài) using namespace std; class MyException {}; class NullException : public MyException {}; int main(int argc, char const *argv[]) {try{throw NullException();}catch (NullException &e){cout << "NullException" << endl;}catch (MyException &e){cout << "MyException" << endl;}return 0; }
標準異常庫:
概述:
由c++提供的一套異常相關(guān)的類
自定義異常類:【了解】
步驟:
-
1 自定義異常類 使其繼承于 exception 獲得其子類
-
2 定義一個變量記錄異常信息
-
3 定義該類的構(gòu)造函數(shù),拷貝構(gòu)造,析構(gòu)函數(shù)【只有析構(gòu)需要判斷是否為空,拷貝不用會重復(fù)釋放野指針出現(xiàn)段錯誤】
-
4 重寫 what 函數(shù)
const char* what() const noexcept {return 步驟2定義的變量 }
-
注意
編譯使用需加 -std=c++11
最需注意的點:
拷貝構(gòu)造
何時觸發(fā)調(diào)用:
當 對象A以對象B進行初始化
如:
class Data {};
Data b; //創(chuàng)建對象
Data a = b; // 將b 賦值給a 對象b 以對象a進行初始化 就是a b 都是單獨的method(Data d)
{
}
method(b);//Data d = b; 將 b 賦值 給 d 觸發(fā)拷貝構(gòu)造 Data method()
{static Data d;return d;
}
Data c = method();//Data c = d 將d 賦值給 c
析構(gòu)函數(shù)
調(diào)用時機: 對象銷毀前
- 生命周期
- 局部變量:隨著所在的函數(shù)的調(diào)用而生成,隨著所在函數(shù)的執(zhí)行完畢而銷毀
- 成員變量:隨著所在的對象的創(chuàng)建而生成,隨著所在的對象銷毀而銷毀
- 全局變量:隨著所在的程序啟動而生成,隨著程序的關(guān)閉而銷毀
- 靜態(tài)局部變量:隨著所在函數(shù)的第一次調(diào)用而生成,隨著所在程序的執(zhí)行完畢而銷毀
- 靜態(tài)成員變量:隨著所在的類的加載而生成,隨著所在程序的執(zhí)行完畢而銷毀
- 靜態(tài)全局變量:隨著所在的程序啟動而生成,隨著程序的關(guān)閉而銷毀
堆區(qū)開辟的內(nèi)存
必須手動回收
class Data
{
};
int *method()
{int *num = (int *)calloc(1, 4);char *str = (char *)calloc(50, 1);// Data d;Data *d = new Data();return num;
}
int main()
{int *p = method();
}
野指針與空指針
> 指針存儲的地址是隨機的 有可能指向 堆區(qū) 有可能指向棧區(qū) 或者其他區(qū) 是不可控的 因為棧區(qū)的會自動釋放 所以當指向棧區(qū)的時候程序不報錯 但是這是不可控的 > 空指針存儲的地址是 NULL 注意:對象的成員變量的值默認為 隨機數(shù)所以 一定注意 拷貝函數(shù)的時候不要判斷是否不為空并釋放因為 成員變量默認是隨機數(shù) 所以就不是 空的 你一旦釋放因為是隨機的所以指針就是野指針 釋放野指針就會觸發(fā)重復(fù)釋放的核心段錯誤 所以 寫的時候 只有 析構(gòu)的時候需要進行判斷 而且要注意繼承的情況
class Data { public:int x;char *str;Data() : x(0), str(NULL){}Data(int x, char *str) : x(x){int len = strlen(str) + 1;this->str = (char *)calloc(len, 1);strcpy(this->str, str);}Data(const Data &d){this->x = d.x;int len = strlen(d.str) + 1;this->str = (char *)calloc(len, 1);strcpy(this->str, d.str);}~Data(){if (str != NULL){free(str);str = NULL;}} }; Data d1; cout << d1.x << endl; Data d2(10, "張三");
虛函數(shù)與純虛函數(shù)
虛函數(shù):
有函數(shù)體,所在的類,可以創(chuàng)建對象,正常繼承,子類重寫父類虛函數(shù),子類對象轉(zhuǎn)換
為父類對象后調(diào)用該函數(shù)執(zhí)行的子類重寫的該函數(shù)
純虛函數(shù):沒有函數(shù)體,所在的類不能直接創(chuàng)建對象,可以繼承,但是子類要么也是抽
象類,要么重寫其所有純虛函數(shù)重寫的純虛函數(shù)也是虛函數(shù)
虛析構(gòu)造與純虛析構(gòu)
-
應(yīng)該釋放的是父 放父 子也釋放
-
放子 只釋放了父 子本身沒釋放
類模版
class 類名 : public 父類名
{
private:成員變量
public:無參構(gòu)造函數(shù)有參構(gòu)造函數(shù)基本類型 用 = 指針類型 考慮要不要深拷貝 拷貝構(gòu)造基本類型 用 = 指針類型考慮要不要深拷貝 virtual 析構(gòu)函數(shù)釋放深拷貝在堆區(qū)的空間get constset 特有函數(shù)
}