C++的型別轉換與異常處理
一 名稱和語法
1 C語言風格:不管什麼型別的轉換統統是:
TYPE b = (TYPE)a;
2 C++風格:
1)static_cast,靜態型別轉換。如int轉換成char
2)reinterpreter_cast,重新解釋型別
3) dynamic_cast,命名上理解是動態型別轉換。如子類和父類之間的多型型別轉換,執行時進行型別識別,把父類轉換成子類。
4)const_cast,字面上理解就是去const屬性
void main01() { double dpi = 3.1415926; int num1 = (int)dpi; //C型別轉換 int num2 = static_cast<int>(dpi); //靜態型別轉換 編譯的時c++編譯器會做型別檢查 int num3 = dpi; //c語言中 隱式型別轉換的地方 均可使用 static_cast<>() 進行型別轉換 char *p1 = "hello...itcast "; int *p2 = NULL; //p2 = static_cast<int*>(p1); // 使用static_cast, 編譯器編譯時,會做型別檢查 若有錯誤 提示錯誤 p2 = reinterpret_cast<int *>(p1); //若不同型別之間,進行強制型別轉換,用reinterpret_cast<>() 進行重新解釋 cout << "p1:" << p1 << endl; //%s指標指向的記憶體空間 cout <<"p2" << p2 << endl; //%d 指標首地址 //總結:通過 reinterpret_cast<>() 和 static_cast<>()把C語言的強制型別轉換 都覆蓋了.. cout<<"hello..."<<endl; system("pause"); return ;
class Animal { public: virtual void cry() = 0; }; class Dog : public Animal { public: virtual void cry() { cout << "汪汪" << endl; } void doHome() { cout << "看家" << endl; } }; class Cat : public Animal { public: virtual void cry() { cout << "喵喵" << endl; } void doThing() { cout << "抓老鼠" << endl; } }; void playObj(Animal *base) { base->cry(); // 1有繼承 2虛擬函式重寫 3 父類指標 指向子類物件 ==>多型 //需求:在這裡能識別子類物件 // dynamic_cast 執行時型別識別 RIIT Dog *pDog = dynamic_cast<Dog *>(base); if (pDog != NULL)//轉換失敗返回NULL { pDog->doHome(); //讓夠 做自己 特有的工作 } Cat *pCat = dynamic_cast<Cat *>(base); //父類物件 ===> 子類物件 //向下轉型 //把老子 轉成 小子 if (pCat != NULL) { pCat->doThing(); //讓夠 做自己 特有的工作 } } void main() { Dog d1; Cat c1; Animal *pBase = NULL; pBase = &d1; playObj(&d1); playObj(&c1); system("pause"); }
#include <iostream> using namespace std; //const char *p 的const修飾 讓p指向的記憶體空間 變成只讀屬性 void printBuf(const char * p) { p1 = const_cast<char *>(p);//由const char * 轉換成char* p1[0] = 'Z' ; //通過p1 去修改了記憶體空間 cout << p << endl; } void main() { char buf[] = "aaaaaaaaafffffddd"; char *myp = "aaaaaaaaafffffddd";//此時*myp指向的記憶體空間時常量,不可修改。 //程式設計師 要確保 p所指向的記憶體空間 確實能修改 ;如果不能修改會帶來災難性後果 //printBuf (buf); printBuf (myp); system("pause"); }
二 異常處理
1 基本思想
1) C++的異常處理機制使得異常的引發和異常的處理不必在同一個函式中
2)異常是專門針對抽象程式設計中的一系列錯誤處理的
3)異常超脫於函式機制,決定了其對函式的跨越式回跳。
4)異常跨越函式
2 基本語法
1)思想
a)若有異常則通過throw操作建立一個異常物件並拋擲。
b)將可能丟擲異常的程式段嵌在try塊之中。控制通過正常的順序執行到達try語句,然後執行try塊內的保護段。
c)如果在保護段執行期間沒有引起異常,那麼跟在try塊後的catch子句就不執行。程式從try塊後跟隨的最後一個catch子句後面的語句繼續執行下去。
d)catch子句按其在try塊後出現的順序被檢查。匹配的catch子句將捕獲並處理異常(或繼續拋擲異常)。
e)如果匹配的處理器未找到,則執行函式terminate將被自動呼叫,其預設功能是呼叫abort終止程式。(程式down)
f)處理不了的異常,可以在catch的最後一個分支,使用throw語法,向上扔。
g)異常機制與函式機制互不干涉,但捕捉的方式是基於型別匹配。
捕捉相當於函式返回型別的匹配,而不是函式引數的匹配,所以捕捉不用考慮一個拋擲中的多種資料型別匹配問題
h)異常捕捉嚴格按照型別匹配
int divide(int x, int y ) //拋異常
{
if (y ==0)
{
throw x; //如果執行了丟擲,則後面的程式碼不再執行
}
return x/y;
}
void main() //接異常
{
try
{
cout << "8/2 = " << divide(8, 2) << endl; ///呼叫
cout << "10/0 =" << divide(10, 0) << endl;
}
catch (int e) //捕捉到上面的異常,同一型別
{
cout << "e" << " is divided by zero!" << endl;
}
catch(...)
{
cout << "其他未知異常" << endl;
}
cout << "ok" << endl;
system("pause");
return ;
}
三 棧解旋(unwinding)
1 定義:異常被丟擲後,從進入try塊起,到異常被拋擲前,這期間在棧上的構造的所有物件,都會被自動析構。析構的順序與構造的順序相反。這一過程稱為棧的解旋(unwinding)。
#include <iostream>
using namespace std;
class Test3
{
public:
Test3(int a=0, int b=0)
{
this->a = a;
this->b = b;
cout << "建構函式do \n";
}
~Test3()
{
cout << "解構函式do \n";
}
private:
int a;
int b;
};
void myDivide() throw (int, char, char *)
{
Test3 t1(1, 2), t2(3, 4);
cout << "myDivide ...要發生異常\n" ;
throw 1;
}
void main()
{
try
{
myDivide();
}
catch (int a)
{
cout << "int型別 異常\n" ;
}
catch (...)
{
cout << " 未知 異常\n" ;
}
cout<<"hello..."<<endl;
system("pause");
return ;
}
四異常介面宣告
1 為了加強程式的可讀性,可以在函式宣告中列出可能丟擲的所有異常型別,例如: void func() throw (A, B, C , D); //函式func()能夠且只能丟擲型別A B C D及其子型別的異常。
2 如果在函式宣告中沒有包含異常介面宣告,則此函式可以拋擲任何型別的異常,例如:void func();
3 一個不拋擲任何型別異常的函式可以宣告為:
void func() throw();
4 如果一個函式丟擲了它的異常介面宣告所不允許丟擲的異常,unexpected函式會被呼叫,該函式預設行為呼叫terminate函式中止程式
五 異常型別及生命週期
1 接受元素時使用異常變數,則進行拷貝構造
2 使用引用的話,catch的是throw的那個物件
3 指標和引用/元素可同時出現,但引用和元素不能同時現如果是指標必須throw的是一個地址(new 申請記憶體)
結論:用引用是最好的
六 標準程式庫異常
C++標準提供了一組標準異常類,這些類以基類exception開始,
標準程式庫丟擲的所有異常,都派生於該基類。
1 案例
// out_of_range
#include "iostream"
using namespace std;
#include <stdexcept>
#include "string"
// out_of_range
class Teacher
{
public:
Teacher(int age)
{
if (age > 100)
{
string s = "年齡太大";
throw out_of_range(s);
}
this->age = age;
}
protected:
private:
int age;
};
void main61()
{
try
{
Teacher t1(102);
}
catch (out_of_range e)
{
cout << e.what() << endl;
}
exception e;
system("pause");
}
class MyException : public exception
{
public:
MyException(const char *p)
{
this->m_p = p;
}
virtual const char * what()
{
cout << "MyException: 型別" << m_p << endl;
return m_p;
}
protected:
private:
const char *m_p;
};
void testMyExcept()
{
throw MyException("函式異常");
}
void main()
{
try
{
testMyExcept();
}
catch (MyException & e)
{
e.what();
}
catch (...)
{
cout << "未知 型別 " << endl;
}
system("pause");
}