强制类型转换
相比于老式强制类型转换:
要是在转换上出错,更容易查找直接搜_cast
将强制类型转换的风险分成不同的等级
1.static_cast< T >
static_cast< T > 用来进用行比较“自然”和低风险的转换,比如整型和实数型、字符型之间互相转换。
不能来在不同类型的指针之间互相转换
不能用于整型和指针之间的互相转换
不能用于不同类型的引用之间的转换
实例:
struct A{
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 的值变为 3
n = static_cast<int>(a); //调用a.operator int, n的值变为 1
p = static_cast<char*>(a); //调用a.operator int *,p的值变为 NULL
n = static_cast<int> (p); //编译错误,static_cast不能将指针转换成整型
p = static_cast<char*>(n); //编译错误,static_cast不能将整型转换成指针
return 0;
}
2. reinterpret_cast< T >
reinterpret_cast< T >
用来进行各种不同类型的指针之间的转换、
不同类型的引用之间转换、
指针和能容纳得下指针的整数类型之间的转换——int类型可以容纳下指针,short不可以容纳下指针
转换的时候,执行的是逐个比特拷贝的操作
struct A{
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指向a的首地址,也就是i的位置,所以可以改变i
r = 200; //把 a.i 变成了 200
cout << a.i << "," << a.j << endl; // 输出 200,100
int n = 300;
A * pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n
pa指向了n,pa可以访问8个字节,但n只有4个,所以会崩溃
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); //两个不同类型的函数指针之间可以互相转换
}
3. const_cast< T >
去除const属性的转换
将const引用转换成同类型的非const引用
将const指针转换为同类型的非const指针
const string s = “Inception”;
string & p = const_cast<string&>(s);
string * ps = const_cast<string*>(&s); // &s的类型是const string *
4. dynamic_cast< T >
dynamic_cast专门用于将多态基类的指针或引用,强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回NULL指针。
dynamic_cast不能用于将非多态基类的指针或引用,强制转换为派生类的指针或引用——也就是说要转的对象必须是多态类型的,也就是类中有虚函数
<>中必须是一个指针或者是引用
这里说的安全是:
有继承关系的向上转型时安全的
有继承关系且先向上转型再向下转型时安全的
struct Base{ //有虚函数,因此是多态基类
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; //会执行
pd = dynamic_cast<Derived*> ( &d); //安全的转换
if( pd == NULL) //此处pd 不会为NULL
cout << "unsafe dynamic_cast2" << endl; //不会执行
return 0;
}
异常处理
1基本格式
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) {//捕获double类的异常
cout << "catch(double) " << d << endl;
}
catch(...) {//能捕获所有类型的异常
cout << "catch(...) " << endl;
}
cout << "finished" << endl;
return 0;
}
2异常的再抛出
struct CException{//自定义异常类!
string msg;
CException(string s):msg(s) { }
};
double Devide(double x, double y){//这个函数的异常没有自处理
if(y == 0)
throw CException("devided 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 << e.msg << endl;
}
cout << "f=" << f << endl;
cout << "finished" << endl;
return 0;
}
3异常类
都是由exception类派生而来
bas_cast
在用 dynamic_cast进行从多态基类对象(或引用),到派生类的引用的强制类型转换时,如果转换是不安全的,则会抛出此异常
如果在进行向下转型之前进行了向上转型就是安全的
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;
}
bad_alloc
在用new运算符进行动态内存分配时,如果没有足够的内存,则会引发此异常
out_of_range
用vector或string的at成员函数根据下标访问元素时,如果下标越界,就会抛出此异常
at函数和[]的区别是前者可以检查下标是否越界
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(100); //抛出out_of_range异常
}
catch (out_of_range& e) {
cerr << e.what() << endl;
}
return 0;
}
识别变量类型
可在运行期进行变量识别
typeid(变量名)
typeid(表达式)
float x ;
typeid(x)==typeid(float)//true
typeid(x)==typeid(double)//false