static_cast、interpret_cast、const_cast 和 dynamic_cast
static_cast用来进行比较“自然”和低风险的转换,比如整型和实数型、字符型之间互相转换。
static_cast不能在不同类型的指针之间互相转换,也不能用于整型和指针之间的互相转换,也不能用于不同类型的引用之间的转换。
static_cast 示例
#include
using namespace std;
class A {
public:
operator int() {
return 1; }
operator char* () {
return NULL; }
};
int main() {
A a;
int n;
const char* p = "New Dragon Inn";
n = static_cast<int>(3.14); //n的值变为3
n = static_cast<int>(a); //调用a.operator int,n的值变为1
p = static_cast<char*>(a); //调用a.operator char*,p的值变为NULL
n = static_cast<int>(p); //编译错误,static_cast不能将指针转换成整型
p = static_cast<char*>(n); //编译错误,static_case不能将整型转换成指针
return 0;
}
reinterpret_cast用来进行各种不同类型的指针之间的转换、不同类型的引用之间的转换、以及指针和能容纳得下指针的整数类型(字节=>4)之间的转换。转换的时候,执行的是逐个比特拷贝的操作。
reinterpret_cast示例
#include
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引用a
r = 200; //把a.i变成了200。
//A是8字节的,r是4字节,所以r引用的是a.i而不是a.j。
cout << a.i << "," << a.j << endl; //输出 200,100
int n = 300;
A* pa = reinterpret_cast<A*>(&n); //强行让pa指向n
pa->i = 400; //n变成400
pa->j = 500; //此条语句不安全,很可能导致程序崩溃
cout << n << endl; //输出 400
long long la = 0x12345678abcdLL;
pa = reinterpret_cast<A*>(la); //la太长,只取低32位0x5678abcd拷贝给pa
unsigned int u = reinterpret_cast<unsigned int>(pa); //pa逐个比特拷贝到u
cout << hex << u << endl; //输出 5678abcd
typedef void(*PF1)(int);
typedef int(*PF2)(int, char*);
PF1 pf1; PF2 pf2;
pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换
return 0;
}
// 输出结果:
// 200, 100
// 400
// 5678abcd
用来进行去除const属性的转换。将const引用转换成同类型的非const引用,将const指针转换为同类型的非const指针时用它。例如:
const string s = "Inception";
string& p = const_cast<string&>(s);
string* ps = const_cast<string*>(&s); //&s的类型是const string*
dynamic_cast示例
#include
#include
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 reinterpret_cast" << endl;
//不会执行
pd = dynamic_cast<Derived*>(&b);
if (pd == NULL)
//结果会是NULL,因为&b不是指向派生类对象,此转换不安全
cout << "unsafe dynamic_cast1" << endl; //会执行
Base* pb = &d;
pd = dynamic_cast<Derived*>(pb); //安全的转换
if (pd == NULL) //此处pd不会为NULL
cout << "unsafe dynamic_cast2" << endl; //不会执行
return 0;
}
// 输出结果:
// unsafe dynamic_cast1
Derived&r=dynamic_cast<Derived&>(b);
//b是基类的对象,即基类的引用。
那该如何判断该转换是否安全?
答案:不安全则抛出异常
– 程序运行中总难免发生错误
– 引起这些异常情况的原因:
– 我们总希望在发生异常情况时
– 通常的做法是:在预计会发生异常的地方,加入相应的代码,但这种做法并不总是适用的
......//对文件A进行了相关的操作
fun(arg,...);//可能发生异常
......
caller该如何知道fun(arg,…)是否发生异常
–没有发生异常,可以继续执行
–发生异常,应该在结束程序运行前还原对文件A的操作
fun(arg,…)是别人已经开发好的代码
– fun(arg,…)的编写者不知道其他人会如何使用这个函数
– fun(arg,…)会出现在表达式中,通过返回值的方式区分是否发生异常
需要一种手段
– 把异常与函数的接口分开,并且能够区分不同的异常
– 在函数体外捕获所发生的异常,并提供更多的异常信息
#include
using namespace std;
int main() {
double m, n;
cin >> m >> n;
try {
cout << "before dividing." << endl;
if (n == 0)
throw - 1; //抛出int类型异常
else
cout << m / n << endl;
cout << "after dividing." << endl;
}
catch (double d) {
cout << "catch(double)" << d << endl;
}
catch (int e) {
cout << "catch(int)" << e << endl;
}
cout << "finished" << endl;
return 0;
}
// 输出:
// 9 6
// before dividing.
// 1.5
// after dividing.
// finished
//捕获任何异常的catch块
#include
using namespace std;
int main() {
double m, n;
cin >> m >> n;
try {
cout << "before dividing." << endl;
if (n == 0)
throw - 1; //抛出整型异常
else if (m == 0)
throw - 1.0; //抛出double型异常
else
cout << m / n << endl;
cout << "after dividing." << endl;
}
catch (double d) {
cout << "catch(double)" << d << endl;
}
catch (...) {
//胜任任何异常
cout << "catch(...)" << endl;
}
cout << "finished" << endl;
return 0;
}
// 输出:
// 9 0
// before dividing.
// catch (...)
// finished
// 0 6
// before dividing.
// catch (double)-1
// finished
如果一个函数在执行的过程中,抛出的异常在本函数内就被catch块捕获并处理了,那么该异常就不会抛给这个函数的调用者(也称“上一层的函数”);如果异常在本函数中没被处理,就会被抛给上一层的函数。
#include
#include
using namespace std;
class CException {
public:
string msg;
CException(string s) :msg(s){
} //构造函数
};
double Devide(double x, double y) {
if (y == 0)
throw CException("devided by zero");
//抛出异常,直接跳到下面的catch(CException e){}处
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 << e.msg << endl;
}
cout << "f=" << f << endl;
cout << "finished" << endl;
return 0;
}
// 输出结果:
// salary < 0
// tax counted
// devided by zero
// f = 1.2
// finished
在用dynamic_cast进行从多态基类对象(或引用),到派生类的引用的强制类型的转换时,如果转换是不安全的,则会抛出此异常。
#include
#include
#include
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; //cerr是标准输出
};
}
int main(){
Base b;
PrintObj(b);
return 0;
}
// 输出:Bad dynamic_cast!
在用new运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常
#include
#include
using namespace std;
int main() {
try {
char* p = new char[0x7fffffff]; //无法分配这么多空间,会抛出异常
}
catch (bad_alloc & e) {
cerr << e.what() << endl;
}
return 0;
}
// 输出:bad allocation
用vector或string的at成员函数根据下标访问元素时,如果下标越界,就会抛出此异常。例如:
#include
#include
#include
#include
using namespace std;
int main() {
vector<int>v(10);
try {
v.at(100) = 100; //抛出out_of_range异常
}
catch (out_of_range & e) {
cerr << e.what() << endl;
}
string s = "hello";
try {
char c = s.at(5); //抛出out_of_range异常
}
catch (out_of_range & e) {
cerr << e.what() << endl;
}
return 0;
}
// 输出:
// invalid vector subscript
// invalid string position