知识点5 C++类型转换
1 静态类型转换(static_cast) 不支持不相关
用于类层次结构中基类和派生类之间指针或引用的转换
进行上行转换:用基类指针、引用转向子类空间(安全)
进行下行转换:用子类指针指向父类(不安全)
#include <iostream>
using namespace std;
class Animal{};
class Dog:public Animal{};
class Other{};
int main()
{
//static_cast作用于基本类型
char ch = 'a';
double d = static_cast<double>(ch);
cout << d <<endl;
//static_cast作用于自定义数据类型(结构体、类)
//上行转换 安全
Animal *p = static_cast<Animal*> (new Dog);
//下行转换 不安全 越界
Dog *p1= static_cast<Dog *>(new Animal);
//static_cast 不能作用于不相关的类之间的转换
//Animal*p2 = static_cast<Animal*>(new Other);
return 0;
}
2 动态转换dynamic_cast 不支持基本类型 不支持不安全 不支持不相关
用于类层次的上行、下行转换
#include <iostream>
using namespace std;
class Animal{};
class Dog:public Animal{};
class Other{};
int main()
{
//dynamic_cast 不支持基本类型
char ch = 'a';
//double d = dynamic_cast<double>(ch);//err
//dynamic_cast上行转换是安全的(父类指针指向子类空间)
Animal *p1 = dynamic_cast<Animal*> (new Dog);
//dynamic_cast下行转换不安全(子类指针转向父类空间)
//Dog *p2 = dynamic_cast<Dog*> (new Animal);//err
//dymanic_cast不支持没有关系的类型转换
//Animal *p3 = dynamic_cast<Animal*> (new Other);//err
return 0;
}
3 常量转换const_cast 不支持非指针和引用转换
#include <iostream>
using namespace std;
class Animal{};
class Dog:public Animal{};
class Other{};
int main()
{
const int *p = NULL;
int *p1 =const_cast<int*>(p);
int *p2 = NULL;
const int *p3 = const_cast<const int *> (p2);
//const_cast 不支持非指针或者非引用的转换
const int a = 100;
//int b = const_cast<int>(a);//err
//常引用转换成普通引用
int data = 100;
const int &ob = data;
int &ob2 = const_cast<int&>(ob);
return 0;
}
4 重新解释转换reinterpret_cast 不支持基本类型以外其他都支持
#i#include <iostream>
using namespace std;
class Animal{};
class Dog:public Animal{};
class Other{};
int main()
{
//reinterpret_cast 不支持基本数据类型
char ch ='a';
//double d = reinterpret_cast<double>(ch);//err
//reinterpret_cast 支持不相关类型间的转换
Animal *p1 = reinterpret_cast<Animal *>(new Other);
//上行转换
Animal *p2 = reinterpret_cast<Animal *>(new Dog);
//下行转换
Dog *p3 = reinterpret_cast<Dog *>(new Animal);
return 0;
}
知识点6 异常的概述
常见的异常:除数为0溢出,数组下标越界,所需要读取的文件不存在,空指针,内存不足等等
C++如果抛出异常不捕获处理,程序直接崩溃退出
1、C语言通过返回值来判断程序运行状态容易忽略,也容易与正常返回结果混淆
2.C++抛出异常并捕获
抛出异常:thorw
捕获异常:try……catch
注意:异常机制和函数机制互不干涉,但是捕获方式是通过严格类型匹配的
#include <iostream>
using namespace std;
int myDiv(int a, int b)
{
if(b == 0)
throw 0;//抛出异常
return a/b;
}
int main()
{
try{
int ret = myDiv(10,0);
cout << "ret = " << ret << endl;
}
catch(int e)//只捕获抛出int类型的异常
{
cout << "捕获到int类型异常 e = " << e << endl;
}
catch(float e)//只捕获抛出float类型的异常
{
cout << "捕获到float类型异常 e = " << e << endl;
}
catch(char e)//只捕获抛出char类型的异常
{
cout << "捕获到char类型异常 e = " << e << endl;
}
catch (...)//捕获所有异常
{
cout << "捕获到其他异常" << endl;
}
return 0;
}
知识点7 栈解旋
当发生异常时,从进入try块后,到异常被抛掷前,这期间在栈上的构造的所有对象都会被自动析构。析构的顺序与构造的顺序相反,这一过程被称为栈的解旋(unwinding)
#include <iostream>
#include <cstring>
using namespace std;
class Person
{
private:
string name;
public:
Person(string name)
{
this->name = name;
cout << "Person" << name << "构造函数" << endl;
}
~Person()
{
cout << "Person" << name << "析构函数" << endl;
}
};
int main()
{
try{
Person ob1("1_阿尔贝尔");
Person ob2("2_阿尔贝尔");
Person ob3("3_阿尔贝尔");
Person ob4("114514_阿尔贝尔");
throw 10;
}
catch(int)
{
cout << "捕获到int异常" << endl;
}
cout << "其他函数" << endl;
return 0;
}
知识点8 异常的接口声明
把要抛出的异常一一列举出来
为了加强函数的可读性,可以在函数声明中列出可能抛出的异常的所有类型。
如果一个函数抛出了它异常接口声明中所不允许抛出的异常,unexpected函数会被调用,该函数会默认调用terminate函数中断程序
void fun() throw(int,char,char*)//只抛出int,char,char*异常
void fun() throw()//不抛出异常
知识点9 异常的生命周期
#include <iostream>
using namespace std;
class MyException
{
public:
MyException()
{
cout << "异常构造" << endl;
}
MyException(const MyException &ob)
{
cout << "异常拷贝构造" << endl;
}
~MyException()
{
cout << "异常析构" << endl;
}
};
int main()
{
try{
MyException ob;
throw ob;
}
catch(MyException)
{
cout << "捕获到MyException异常" << endl;
}
cout << "其他函数" << endl;
return 0;
}
知识点10 标准异常
标准异常类的具体描述:
异常名称 | 描述 |
exception | 所有标准异常类的父类 |
bad_alloc | 当operator new and operator new[],请求分配内存失败时 |
bad_exception | 这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的unexpected函数中若抛出异常,不论什么类型,都会被替换为bad_exception类型 |
bad_typeid | 使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常 |
bad_cast | 使用dynamic_cast转换引用失败的时候 |
ios_base::failure | io操作过程出现错误 |
logic_error | 逻辑错误,可以在运行前检测的错误 |
runtime_error | 运行时错误,仅在运行时才可以检测的错误 |
logic_error的子类:
异常名称 | 描述 |
length_error | 试图生成一个超出该类型最大长度的对象时,例如vector的resize操作 |
domain_error | 参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数 |
out_of_range | 超出有效范围 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
runtime_error的子类:
异常名称 | 描述 |
range_error | 计算结果超出了有意义的值域范围 |
overflow_error | 算术计算上溢 |
underflow_error | 算术计算下溢 |
invalid_argument | 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常 |
- #include <iostream>
- #include <exception>
- using namespace std;
- class Person
- {
- private:
- int age;
- public:
- Person(int age)
- {
- if(age<0 || age>150)
- throw out_of_range(“age无效”);
- this->age = age;
- }
- };
- int main()
- {
- try{
- Person ob(200);
- }
- catch(exception &e)
- {
- cout << “捕获到异常:” << e.what() <<endl;
- }
- cout << “其他函数” << endl;
- return 0;
- }
知识点11 cin的拓展
1.cin.get获取一个字符 cin.getline获取带空格的字符串
- #include <iostream>
- using namespace std;
- int main()
- {
- //cin的基本用法
- int data = 0;
- cin >> data;
- cout << data << endl;
- //获取一个字符
- char ch;
- cin >> ch;
- cout << “ch = ” << ch << endl;
- //获取一个字符
- char ch1 = ‘\0’;
- ch1 = cin.get();//获取一个字符
- cout << “ch1 = ” << ch1 << endl;
- //获取字符串
- char name[128] = “”;
- cin >> name;//遇到空格、回车自动结束
- cout << “name = ” << name << endl;
- //获取一行
- char name2[128] = “”;
- cin.getline(name2,sizeof(name2));//可以获取带空格的字符串
- cout << “name2 = ” << name2 << endl;
- return 0;
- }
2.cin.ignore忽略缓冲区的前n个字符
- char name[128] = “”;
- cin.ignore(2);//忽略前两个字节
- cin >> name;
- cout << “name = ” << name << endl;
3.cin.putback放回缓冲区
- char ch = 0;
- ch = cin.get();
- cout << “ch = ” << ch << endl;
- cin.putback(ch);//将ch的字符放回缓冲区
- char name[32] = “”;
- cin >>name;
- cout << “name = ” << name << endl;
- return 0;
4.cin.peek偷窥
- char ch = 0;
- ch = cin.peek();
- cout << “偷窥缓冲区的数据为:” << ch << endl;
- char name[32] = “”;
- cin >> name;
- cout << “name = ” << name << endl;
- return 0;