日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++-运行时类型信息,异常(day11)

發布時間:2024/4/17 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++-运行时类型信息,异常(day11) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、運行時類型信息

1、typeid運算符

頭文件:#include<typeinfo>

C++的標準頭文件,都對應相應的類

//sizeof(類型/變量/表達式),返回內存大小

typeid(類型/變量/表達式),返回typeinfo類型的對象,其中包含name()成員函數,返回字符串,描述類型信息

雖然與函數調用形式相同,但是typeid是操作符。

?

int x;cout<<typeid(int).name()<<endl;//不同編譯器的字符串描述可能不同cout<<typeid(x).name()<<endl;

cout<<typeid(int* [5]).name()<<endl;

cout<<typeid(int(*) [5]).name()<<endl;//數組指針

?

class X{protected:virtual void foo(void){} };class Y{protected:void foo(void){}  }class Z{void foo(void){}};void func(X& x){/*if(!strcmp(typeid(x).name(),"1Y")){cout<<"Y"<<endl;}else if(!strcmp(typeid(x).name(),"1Z")){cout<<"Z"<<endl;}else(!strcmp(typeid(x).name(),"1X")){cout<<"X"<<endl;}*/ //typeinfo類中已經重載的operator==函數if(!strcmp(typeid(x).==typeid(Y))){cout<<"Y"<<endl;}else if(!strcmp(typeid(x)==typeid(Z))){cout<<"Z"<<endl;}else(!strcmp(typeid(x)==typeid(X)){cout<<"X"<<endl;}}

?

注意:

  typeid的使用是基于基類中存在虛函數,并且子類繼承并覆蓋了虛函數。否則typeid無法獲取類型信息。

?

2、動態類型轉換運算符(day3)

目標類型變量=dynamic_cast<目標類型>目標源類型變量

使用場景:適用于具有多態繼承關系的父子類指針或者引用之間的顯式轉換。

?

class A{virtual void foo(void){}};class B:publicA{void foo(void)};class C:publicA{void foo(void)};class D{};B b;A* pa=&b;//B* pb=pa;//向下轉換,編譯報錯//B* pb=static_cast<B*>(pa);//ok B* pb=dynamic_cast<B*>(pa);//ok//C* pc=static_cast<C*>(pa);//因為pa已經指向了B*的類型,雖然可以通過,但是不安全 C* pc=dynamic_cast<C*>(pa);//程序執行階段進行轉換,而靜態轉換是程序編譯階段進行轉換,雖然不報錯,但是pc的地址將為空。執行時動態類型轉換會做類型檢查,如果是無關的類,無法轉換。 D* pc=dynamic_cast<D*>(pa);//也為空//可以打印出pa,pb,pc的地址,可見pc為空地址//使用引用的不合理類型動態轉換時,執行時會進程會被終止

?

?

dynamic_cast在轉換的過程中,會根據多態的特性,檢查父子類的指針或者引用目標類型是否一致,如果一致則轉換成功,否則轉換失敗,如果是指針轉換,則返回NULL,如果是引用轉換,則拋出異常“bad_cast”

?


?

?

二、異常(Exception)

1、常見錯誤

  1)語法錯誤

  2)邏輯錯誤

  3)功能錯誤

  4)設計缺陷

  5)需求不符

  6)環境異常

  7)操作不當

?

2、C的錯誤處理機制

1)通過返回值表示錯誤

class A{public:A(void){cout<<"A::A()"<<endl;}~A(void){cout<<"~A::A()"<<endl;}};//通過返回值表示錯誤int func3(void){A a;FILE* fp=fopen("none.text","r");if(fp==NULL){cout<<"file open error!"<<endl;return -1;}fclose(fp)return 0;}int func2(void){A a;if(func3()==-1){return -1;}return 0;}int func1(void){A a;if(func2()==-1){return -1;}//... retuern 0;}int main(void){if(func1()==-1){return -1;}//...return 0;}//通過返回值表示錯誤 棧區對象在出現異常之后,能夠正常釋放

?

2)通過遠程跳轉來處理錯誤

?


jmp_buf g_env;//包含頭文件#include<setjmp.h>
class A{public:A(void){cout<<"A::A()"<<endl;}~A(void){cout<<"~A::A()"<<endl;}};//通過返回值表示錯誤int func3(void){A a;FILE* fp=fopen("none.text","r");if(fp==NULL){longjmp(g_env,-1);}//...fclose(fp)return 0;}int func2(void){A a;func3();return 0;}int func1(void){A a;func2();//...retuern 0;}int main(void){if(setjmp(g_nev)==-1){//先設置g_env,如果有錯誤,會再次直接跳轉到此處
    cout<<"file open error!"<<endl;
  }
  func1();//...return 0;} ?

?

使用遠程跳轉棧區對象無法得到釋放

?

?

?通過返回值表示錯誤

  優點:函數調用路徑中所有的局部對象都能夠得到正常的析構,不會內存泄漏。

  缺點:錯誤處理流程比較復雜,逐層判斷,代碼臃腫

通過鹽城跳轉機制處理錯誤

  優點:不需要逐層判斷,實現一步到位的錯誤處理,代碼精簡

  缺點:函數調用的路徑中布局對象失去被析構的機會,形成內存析構

?

?3、C++的異常處理機制

?  結合C中兩種錯誤處理的優點,同時避免他們的缺點,在形式上實現一步到位的錯誤處理,無需逐層判斷返回值,所有的局部對象得到正常的析構。

class A{public:A(void){cout<<"A::A()"<<endl;}~A(void){cout<<"~A::A()"<<endl;}};//通過返回值表示錯誤int func3(void){A a;FILE* fp=fopen("none.text","r");if(fp==NULL){throw -1//拋出異常   }//... fclose(fp)return 0;}int func2(void){A a;func3();return 0;}int func1(void){A a;func2();//... retuern 0;}int main(void){try{func1();//...出現異常,此處將不會得到執行,直接跳轉到catch   }catch(int ex/*拋出的異常數據類型*/){cout<<"file open error!"<<endl;return -1;}//...return 0;}

?

如果執行到throw語句,會逐層返回執行},并且內存會得到釋放

?

4、C++異常語法

(1)異常拋出

  throw 異常對象;//拋出的異常會被放到安全區,無法手動訪問

如:

  throw -1;

  throw "file error";

  throw 對象;

  

(2)異常捕獲

  try{

    //可能引發異常的語句

  }

  catch(異常類型1){

    //異常類型1的處理

  }

  catch(異常類型2){

    //異常類型2的處理

  }

  ...

  catch(.../*可以匹配任意類型*/){

    //針對其他類型的處理

  }

  

class FileError{ public:FileError(){}FileError(const string& file,int line):m_file(file),m_line(line){cout<<"拋出位置"<<m_file<<","<<m_line;} private:string m_file;int m_line; }; class A{public:A(void){cout<<"A::A()"<<endl;}~A(void){cout<<"~A::A()"<<endl;}};//通過返回值表示錯誤int func3(void){A a;FILE* fp=fopen("none.text","r");if(fp==NULL){throw FileError(__FILE__,__LINE__);/*注意,是雙下劃線,而不是單下劃線__FILE__ 包含當前程序文件名的字符串__LINE__ 表示當前行號的整數__DATE__ 包含當前日期的字符串__STDC__ 如果編譯器遵循ANSI C標準,它就是個非零值__TIME__ 包含當前時間的字符串*///FileError ex;//throw ex;throw "file error";throw -1//拋出異常   }//... fclose(fp)return 0;}int func2(void){A a;func3();return 0;}int func1(void){A a;func2();//... retuern 0;}int main(void){try{func1();//...出現異常,此處將不會得到執行,直接跳轉到catch   }catch(int ex/*拋出的異常數據類型*/){cout<<"file open error!"<<endl;return -1;}catch(const char* ex){cout<<"file error!"<<endl;return -1;}catch(FileError& ex){//如果拋出的是對象,最好是用引用cout<<"FileError"<<endl;return -1;}//...return 0;}

?

注意:

  (1)如果沒有類型可以匹配,那么拋出的異常將被系統鎖捕獲,進程將被回收。內存被釋放

  (2)如果有兩個連續的throw語句,只會被執行一個,因為在throw時候,直接跳轉到}執行。

  (3)如果拋出的是類的對象,最好使用引用。

  (4)在面向對象的編程中,一般都是拋出對象,而不是整數或者字符串等基本類型,因為類比基本類型可以存儲更多信息。比如日志等 

?

5、異常-擴展

class A{};class B:public A{};void func(void){//...throw(B);//throw(A); }int main(void){try{func();}catch(A& ex){//向上造型可以匹配B類異常 cout<<"捕獲到A類異常"<<endl;return -1;}catch(B& ex){cout<<"捕獲到B類的異常"<<endl;return -1;}return 0;}//上述代碼中B異常將無法被捕獲,無論是拋A,還是拋B,正確的處理方式應該把子類的異常捕獲放在基類之前,防止發生向上造型。

?

注意:

  catch的匹配是自上而下進行匹配,而不是選擇最優匹配,所以應該把子類的異常捕獲放在基類之前,防止發生向上造型。

?

?

6、異常說明
1)可以在函數原型中增加異常說明,說明該函數可能拋出的異常類型。提前通知編譯器,函數會拋出的異常類型
   返回類型 函數名(形參表)[cosnt]throw(異常類型表){...}
  不加異常說明列表,異常也能夠被正常捕獲,和不加的區別在于,如果函數拋出了與說明列表不符的類型,這個異常將不會被捕獲。自然也會被系統所捕獲。

2)函數的異常說明只是一種承諾,表示該函數不會拋出說明列表意外的類型。意外的異常將會被系統所捕獲。

3)如果不寫異常說明,表示可以拋出任何異常

4)空異常說明,throw(),表示不會拋出任何異常。

5)如果函數的聲明和定義分開,在聲明和定義部分都要加上異常說明。并且說明列表必須相同,但是順序可以改變。


7、異常說明與多態 class FileError{}; class MemError{};class Base{ public:virtual void func(void)throw(FileError,MemError){}   };class Derived:public Base{ public:void func(void){}//虛函數覆蓋會失敗,因為子類的虛函數覆蓋函數沒有異常說明,這里異常說明范圍可以縮小,但是不能擴大 };

如果基類中的虛函數帶有異常說明,它的子類中,該函數的覆蓋版本不能比基類版本拋出更多異常,否則編譯器報出“放松throw限定”錯誤

?

轉載于:https://www.cnblogs.com/ptfe/p/11300823.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的C++-运行时类型信息,异常(day11)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。