目录
一. 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;
}
}