强制类型转换&&异常处理——郭炜

强制类型转换

相比于老式强制类型转换:
	要是在转换上出错,更容易查找直接搜_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 
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值