C++基础知识(九)--- 类型转换 & 异常

本文详细介绍了C++中的类型转换,包括静态转换、动态转换、常量转换和重新解释转换,并通过示例代码进行解析。此外,文章还深入探讨了C++异常处理机制,包括异常的优势、语法、栈解旋以及异常变量的生命周期,同时讲解了如何自定义异常类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一. C++类型转换(了解)

1. 静态转换

2. 动态转换

3. 常量转换

4. 重新解释转换

二. 异常

1. C语言处理异常的方法:

2. 异常的语法

3. 异常的优势

4. 异常的严格类型匹配

5. 异常的接口说明

6. 栈解旋(重点)

7. 异常变量的生命周期

(1)产生三个对象

(2)产生两个对象

(3)产生一个对象(常用)

(4)注意

8. 异常的多态

9. C++标准异常库

10. 仿照标准异常库写自己的异常类


一. C++类型转换(了解)

就是将一种数据类型转换成另一种数据类型。例如,如果将一个整型值赋给一个浮点类型的变量,编译器会暗地里将其转换成浮点类型。

标准C++提供了一个显式的转换语法,来替代C风格的类型转换。

C++风格的强制转换可以更好地控制转换过程。

1. 静态转换

(1)用于基本数据类型之间的转换。

void test()
{
	char a = 'a';
	double b = static_cast<double>(a);
}

(2)用于类层次结构中父类和子类之间指针或引用的转换。

父类转子类是不安全的;子类转父类是安全的。

 

2. 动态转换

主要用于类层次间的上行转换和下行转换;

基础类型不能使用动态转换;

向上转时,dynamic_cast 和 static_cast 的效果是一样的;

向下转时,dynamic_cast 具有类型检查的功能,比static_cast更安全;

3. 常量转换

用来修改类型的 const 属性;

常量指针被转换成非常量指针,仍然指向原来的对象;

常量引用被转换成非常量引用,仍然指向原来的对象;

不能直接对非指针和非引用的变量使用const_cast操作符去直接移除它的const。

void test()
{
	const int* p = NULL;
	//const -> 非const
	int* newP = const_cast<int*>(p);
	//非const -> const
	int* q = NULL;
	const int* newQ = const_cast<const int*>(q);
}

4. 重新解释转换

最不安全的转换。

主要用于将一种数据类型从一种类型转换为另一种类型。

可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针。

void test()
{
	//int转换成指针
	int a = 1;
	int* p = reinterpret_cast<int *>(a);
	//也可以对没有继承关系的类之间进行转换
	Father* f = NULL;
	Other* o = reinterpret_cast<Other*>(f);
}

二. 异常

异常处理就是处理程序中的错误。所谓错误是指在程序运行过程中发生的一些异常事件(如:除0溢出、数组下标越界、所要读取的文件不存在、空指针、内存不足等)。

1. C语言处理异常的方法:

① 使用整型的返回值标识错误;② 使用 error 宏去记录错误。

 缺陷:

  •  返回值意思不明确;
  • 返回值只有一个,只能返回一条信息;
  • 返回值可以忽略。

C++的异常处理可以解决这些问题。

2. 异常的语法

 

3. 异常的优势

  • 若有异常则通过 throw 操作创建一个异常对象并抛出;
  • 将可能抛出异常的程序段放到 try 块之中;
  • 如果在 try 段执行期间没有引起异常,那么跟在 try 后面的 catch 语句就不会执行;
  • catch 语句会根据出现的先后顺序被检查,匹配的 catch 语句捕获并处理异常;
  • 如果匹配的 catch 处理未找到,则运行函数 terminate 将自动被调用,并终止程序;
  • 返回值只能返回一条信息,但是对象有成员函数,可以包含多条信息;

C++的异常处理使得异常的引发和处理不必在一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以在适当的位置设计对不同类型异常的处理。

4. 异常的严格类型匹配

int func(int a, int b)
{
	if (b == 0)
	{
		throw 10; //抛出int类型的异常
		throw 'a'; //抛出char类型的异常
		throw "hello"; //抛出char*类型的异常
		string str="hahaha";
		throw str; 
	}
	return a / b;
}
void test()
{
	int a = 10;
	int b = 0;
	try
	{
		func(a, b);
	}
	catch (int)
	{
		cout << "接收一个int类型的异常" << endl;
	}
	catch (char)
	{
		cout << "接收一个char类型的异常" << endl;
	}
	catch (char*)
	{
		cout << "接收一个char*类型的异常" << endl;
	}
	catch (...)
	{
		cout << "接收其他类型的异常" << endl;
	}
}

5. 异常的接口说明

void func() throw(int, char) //只允许抛出 int 或者 char 异常
{
	throw 10; 
}

6. 栈解旋(重点)

 运行结果如下,可以看出,进行了两次构造,只进行了一次析构,所以发生了栈解旋。

Maker构造
Maker拷贝构造
Maker析构
接收一个Maker异常
Maker析构

7. 异常变量的生命周期

使用上边的 Maker 类。

(1)产生三个对象

(2)产生两个对象

(3)产生一个对象(常用)

 

(4)注意

8. 异常的多态

//异常的基类
class Father
{
public:
	virtual void printM()
	{}
};
//1.有继承
class SonNULL :public Father
{
public:
	virtual void printM()  //2.重写父类的虚函数
	{
		cout << "空指针异常" << endl;
	}
};
class SonOut :public Father
{
public:
	virtual void printM()
	{
		cout << "越位溢出" << endl;
	}
};


void func(int a, int b)
{
	if (a == 0)
	{
        throw SonNULL();
	}
	if (b == 0)
	{
		throw SonOut();
	}
}

void test()
{
	int a = 0;
	int b = 1;
	try
	{
		func(a,b);
	}
	catch(Father& f)  //3.父类引用指向子类对象
	{
		f.printM();
	}
}

9. C++标准异常库

10. 仿照标准异常库写自己的异常类

class Myout_of_range :public exception
{
public:
	Myout_of_range (const char* errinfo)
	{
		//const char*转换为string
		this->m_info = string(errinfo);
	}
	Myout_of_range (const string errinfo)
	{
		this->m_info = errinfo;
	}
	const char* what() const
	{
		//把string转换成const char*
		return this->m_info.c_str();
	}
public:
	string m_info;
};

class Maker
{
public:
	Maker(int age)
	{
		if (age < 0)
		{
			throw Myout_of_range ("自己的异常类,age is not correct");
		}
		else
		{
			this->age = age;
		}
	}
public:
	int age;
};

void test()
{
	try
	{
		Maker m(-1);
	}
	catch(Myout_of_range& my)
	{
		cout << my.what() << endl;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值