程式設計與演算法(三)第十週 c++新特性和c++高階主題(3)
阿新 • • 發佈:2018-12-15
強制型別轉換 :static_cast、interpret_cast、const_cast、dynamic_cast
1、static_cast:static_cast 用來進行比較“自然”和低風險的轉換,比如整型和實數型、字元型之間的互相轉換。static_cast不能用來在不同型別的指標之間互相轉換,也不能用於不同型別的引用之間的轉換,也不能用於不同型別的引用之間的轉換。
#include <iostream>
using namespace std;
class A{
public:
operator int(){return 1;}
operator char *(){return NULL;}
};
int main()
{
A a;
int n;
char *p="New Dragon Inn";
n = static_cast<int>(3.14);
n = static_cast<int>(a);
p = static_cast<char *>(a);
// n = static_cast<int>(p);//編譯錯誤,static_cast不能將指標轉換成整型
// p = static_cast<char*>(n);//編譯錯誤,static_cast不能將整型轉換成指標
return 0;
}
2、reinterpret_cast:reinterpret_cast用來進行各種不同型別的指標之間的轉換、不同型別之間轉換、以及指標和能容納得下指標的整數型別之間的轉換。轉換的執行的是逐個位元拷貝的操作
#include <iostream>
using namespace std;
class A{
public:
int i;
int j;
A(int n):i(n),j(n){}
};
int main()
{
A a(100);
int& r = reinterpret_cast<int& >(a);
r=200;//將a.i改變成了200
cout<<a.i<<","<<a.j<<endl;
int n=300;
A*pa=reinterpret_cast<A*>(&n);
pa->i=400;
pa->j=500;
cout<<n<<endl;
long long la=0x12345678abcdLL;
pa = reinterpret_cast<A*>(la);//la 太長,只取低32位5678abcd拷貝給pa
//下面兩句在課程中是貌似是可以的,不過,在我電腦上有問題。。
// unsigned int u = reinterpret_cast<unsigned int>(pa);
// cout<<hex<<u<<endl;
typedef void(*PF1)(int);
typedef int(*PF2)(int, char *);
PF1 pf1;
PF2 pf2;
pf2 = reinterpret_cast<PF2>(pf1);
}
//輸出:
/*
200,100
400
*/
3、const_cast:用來進行去除const屬性的轉換。將const引用轉換成同類型的非const引用。將const指標轉換為同類型的非const指標時用題它,如:
const string s="Inception";
string &p=const_cast<string &>(s);
string *ps = const_cast<string *>(&s);
4、dynamic_cast
dynamic_cast專門用於將多型基類指標或引用,強制轉換成派生類的指標或引用,而且能夠檢測轉換的安全性。對於不安全的指標轉換,轉換結果返回NULL指標。dynamic_cast不能用於將非多型基類的指標或引用,強制轉換為派生類的指標或引用。(多型基類:包含虛擬函式的基類)
#include <iostream>
#include <string>
using namespace std;
// 多型基類
class Base{
public:
virtual ~Base(){}
};
class Derived:public Base{};
int main()
{
Base b;
Derived d;
Derived *pd;
pd = reinterpret_cast<Derived*>(&b);
if(pd==NULL)
{
//此處pd不會為NULL
// reinterpret_cast不檢測安全性,總是進行轉換
cout<<"unsafe"<<endl;
//不會執行
}
pd = dynamic_cast<Derived*>(&b);
if(pd==NULL)
{
//結果會是NULL因為&b不是指向派生類物件,此處轉換不安全
cout<<"unsafe dynamic_cast 1"<<endl;
}
Base *pb=&d;
pd = dynamic_cast<Derived*>(pb);
if(pd==NULL)
{
cout<<"unsafe dynamic_cast 2"<<endl;
}
return 0;
}
/*
* 輸出:
unsafe dynamic_cast 1
*/
dynamic_cast:實現基類引用到派生類引用之間的轉換
Derived & r=dynamic_cast<Derived &>(b);
如何判斷改轉換是否安全呢?答案:不安全則丟擲異常
異常處理
#include <iostream>
using namespace std;
int main()
{
double m, n;
cin>>m>>n;
try{
// try 塊
cout<<"before dividing."<<endl;
// 一旦到throw那try就停止執行,進catch塊
//
if(n==0)
throw -1;//丟擲int型別異常,
else if(m==0)
throw -1.0;
else
cout<<m/n<<endl;
cout<<"after dividing"<<endl;
}
//catch從上到下檢測
catch(double d) {
//捕獲double型異常
cout<<"catch(double)"<<d<<endl;
}
catch(int e){
//捕獲整型異常
cout<<"catch(int)"<<e<<endl;
}
catch(...){
//捕獲任何型別的異常
cout<<"catch(...)"<<endl;
}
cout<<"finished"<<endl;
return 0;
}
0 6
before dividing.
catch(double)-1
finished
異常的再丟擲
如果一個函式在執行的過程中,丟擲的異常在本函式內就被catch塊捕獲並處理了,那麼該異常就不會拋給這個函式的呼叫者(也稱“上一層的函式”);如果異常在本函式中沒被處理,就會被拋給上一層的函式
#include <iostream>
#include <string>
using namespace std;
class CException {
public:
string msg;
CException(string s) : msg(s) {}
};
double Devide(double x, double y) {
if (y == 0)
throw CException("devide by zero");
cout << "in Devide" << endl;
return x / y;
}
int CountTax(int salary){
try{
if(salary<0)
throw -1;
cout<<"counting tax"<<endl;
}
catch(int)
{
cout<<"salary<0"<<endl;
}
cout<<"tax counted"<<endl;
return salary*0.15;
}
int main()
{
double f=1.2;
try {
//下面這個異常被處理了
CountTax(-1);
//下面這個異常被捕獲
f=Devide(3,0);
cout<<"end of try block"<<endl;
}
catch(CException e) {
cout<<"in main catch "<<e.msg<<endl;
}
cout<<"f="<<f<<endl;
cout<<"finished"<<endl;
return 0;
}
salary<0
tax counted
in main catch devide by zero
f=1.2
finished
c++標準異常類:c++標準庫中有一些類代表異常,這些類都是從exception類派生而來。常用的幾個異常類如下:
bad_cast:在用dynamic_cast進行從多型基類物件(或引用),到派生類的引用的強制型別轉換時,如果轉換是不安全的,則會丟擲此異常。
#include <iostream>
#include <stdexcept>
#include <typeinfo>
using namespace std;
class Base{
virtual void func(){}
};
class Derived:public Base{
public:
void Print(){}
};
void PrintObj(Base& b)
{
try{
//基類引用強制轉為派生類引用
Derived& rd = dynamic_cast<Derived&>(b);
// 此轉換若不安全,會丟擲bad_cast異常
rd.Print();
}
catch(bad_cast& e){
cerr<<e.what()<<endl;
}
}
int main()
{
Base b;
PrintObj(b);
return 0;
}
// 輸出:std::bad_cast
bad_alloc:在用new運算子進行動態記憶體分配時,如果沒有足夠的記憶體則會引發此異常。
#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
try{
char *p = new char[0x7ffffffff];
//無法分配這些空間,會拋異常
}
catch(bad_alloc& e)
{
cerr<<e.what()<<endl;
}
return 0;
}
// 輸出:std::bad_alloc
out_of_range 用vector或string的at成員函式根據下標訪問元素時,如果下標越界,就會丟擲此異常。例如:
#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using namespace std;
int main()
{
vector<int> v(10);
try{
// 如果[]不檢測下標越界,at()會檢測,所以速度慢
v.at(100)=100;
// 丟擲out_of_range的異常
}
catch(out_of_range& e){
cerr<<e.what()<<endl;
}
string s="hello";
try{
char c=s.at(100);
//丟擲out_of_range的異常
}
catch(out_of_range& e){
cerr<<e.what()<<endl;
}
return 0;
}
//輸出:
// vector::_M_range_check: __n (which is 100) >= this->size() (which is 10)
// basic_string::at: __n (which is 100) >= this->size() (which is 5)