Review cpp day10
Posted 达少Rising
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Review cpp day10相关的知识,希望对你有一定的参考价值。
回顾:
Review cpp day01
Review cpp day02
Review cpp day03
Review cpp day04
Review cpp day05
Review cpp day06
Review cpp day07
Review cpp day08
Review cpp day09
二十三、运行时的类型信息//了解
1、typeid操作符
#include <typeinfo>
typeid(类型/对象);
- 返回typeinfo的对象,用于描述类型信息,里面包含一个name的成员函数,可以将类型信息转化为字符串形式。
- typeinfo提供了对“==”和“!=”操作符重载的支持,通过它们可以直接进行类型之间的比较。
06typeid.cpp
#include <iostream>
#include <typeinfo>
#include <cstring>
using namespace std;
class X{
virtual void foo(){}
};
class Y:public X{
void foo(){}
};
class Z:public X{
void foo(){}
};
void func(X& x){
//if(!strcmp(typeid(x).name(), "1Y")){
if(typeid(x) == typeid(Y)){
cout << "针对Y对象处理" << endl;
}
//else if(!strcmp(typeid(x).name(), "1Z")){
else if(typeid(x) == typeid(Z)){
cout << "针对Y对象处理" << endl;
}
else{
cout << "针对X对象处理" << endl;
}
}
int main(void){
int a;
cout << typeid(int).name() << endl;//i
cout << typeid(a).name() << endl;//i
int arr[10];
cout << typeid(arr).name() << endl;//A10_i;
int* p;
cout << typeid(p).name() << endl;//Pi
int *arr1[10];
int (*arr2)[10];
cout << typeid(arr1).name() << endl;//A10_Pi
cout << typeid(arr2).name() << endl;//PA10_i
cout << typeid(int (*)(char)).name() << endl;//PFicE
cout << typeid(Y).name() << endl;//1Y
Y y;
Z z;
X x;
func(y);
func(z);
func(x);
return 0;
}
2、动态类型转换操作符
- 语法:
目标类型变量 = dynamic_cast<目标类型>(源类型变量);
- 适用场景:用于具有多态继承关系的父子类指针或引用的显式转换。
注: 在转换过程中,会检查目标对象的类型和期望转换的类型是否一致,如果一致转换成功,否则转换失败。如果转换的是指针,返回NULL表示失败,如果转换的是引用,抛出“bad_cast”异常表示转换失败。
07dynamic.cpp
#include <iostream>
using namespace std;
class A{
virtual void foo(void){}
};
class B:public A{
void foo(void){}
};
class C:public A{
void foo(void){}
};
int main(void){
B b;
A* pa = &b;
//B* pb = static_cast<B*>(pa);//合理
//C* pc = static_cast<C*>(pa);//编译器能编译通过,但这种转换不合理
B* pb = dynamic_cast<B*>(pa);
//C* pc = dynamic_cast<C*>(pa);//error,可以发现转换不合理而报错
cout << "pa=" << pa << endl;
cout << "pb=" << pb << endl;
A& ra = b;
//C& rc = dynamic_cast<C&)(ra);//error,可以发现转换不合理而报错
cout << "pc=" << pc << endl;//NULL
return 0;
}
二十四、异常(EXception)
1、开发中常见的错误
- 1)语法错误
- 2)逻辑错误
- 3)功能错误
- 4)设计缺陷
- 5)需求不符
- 6)环境异常
- 7)操作不当
2、传统C中错误处理机制//了解
- 1)通过返回值表示错误
- 优点:函数调用路径中所有的局部函数对象都能被正确地析构,不会发生内存泄漏。
- 缺点:错误处理的流程比较复杂,需要逐层判断,代码臃肿。
01error.cpp
#include <iostream>
#include <cstdio>
using namespace std;
class A{
publuc:
A(void){
cout << "A::A()" << endl;
}
~A(void){
cout << "A::~A()" << endl;
}
};
int func3(void){
A a;
FILE* fp = fopen("xx.txt", "r");
if(fp = NULL){
cout << "文件打开失败!" << endl;
return -1;
}
//...
fclose fp;
fp = NULL;
}
int func2(void){
A = a;
if(func3() == -1){
return -1;
}
//...
return 0;
}
int func1(void){
A a;
if(func2 == -1){
return -1;
}
//...
return 0;
}
int main(void){
if(func1 == -1){
return -1;
}
return 0;
}
A::A()
A::A()
A::A()
文件打开失败!
A::~A()
A::~A()
A::~A()
- 2)通过远程跳转处理错误
- 优点:不需要逐层判断,一步到位的错误处理,代码精炼。
- 缺点:函数调用路径中的局部对象失去被析构的机会,有内存泄漏的风险。
02error.cpp
#include <iostream>
#include <cstdio>
#include <csetjmp>
using namespace std;
jmp_buf g_env;
class A{
publuc:
A(void){
cout << "A::A()" << endl;
}
~A(void){
cout << "A::~A()" << endl;
}
};
int func3(void){
A a;
FILE* fp = fopen("xx.txt", "r");
if(fp = NULL){
longjmp(g_env, -1);
}
//...
fclose(fp);
fp = NULL;
}
int func2(void){
A a;
func3();
//...
return 0;
}
int func1(void){
A a;
func2();
//...
return 0;
}
int main(void){
if(setjmp(g_env) == -1){
cout << "文件打开失败" << endl;
}
func1();
return 0;
}
A::A()
A::A()
A::A()
文件打开失败!
3、C++异常机制
- 结合两种传统错误处理的优点,同时避免它们的缺点,在形式实现一步到位的错误处理,同时保证所有的局部对象得到正确的析构。
4、异常语法
- 1)异常抛出:
throw 异常对象;
eg:
throw -1;
thow "error";
//--------------------
class FileError();
throw FileError();
- 2)异常捕获
try{
可能引发异常的语句;
}
catch(异常类型1){
针对异常类型1的处理;
}
catch(异常类型2){
针对异常类型2的处理;
}
catch(...){
针对其他异常类型的处理;
}
03error.cpp
#include <iostream>
#include <cstdio>
using namespace std;
class A{
public:
A(void){
cout << "A::A()" << endl;
}
~A(void){
cout << "A::~A()" << endl;
}
};
class FileError{
public:
FileError(const string& file, int line){
cout << "出错位置:" << file << "," << line << endl;
}
};
int func3(void){
A a;
FILE* fp = fopen("xx.txt", "r");
if(fp == NULL){
throw FileError(__FILE__, __LINE__);
throw -1;//抛出异常
cout << "test1" << endl;
}
//...
fclose(fp);
fp = NULL;
return 0;
}
int func2(void){
A a;
func3();
cout << "test2" << endl;
//...
return 0;
}
int func1(void){
A a;
func2();
cout << "test3" << endl;
//...
return 0;
}
int main(void){
try{
func1();
//.....
}
catch(int ex){
if(ex == -1){
cout << "文件打开失败" << endl;
return -1;
}
}
catch(FileError& ex){
cout << "文件打开失败!" << endl;
return -1;
}
return 0;
}
A::A()
A::A()
A::A()
出错位置:03exception.cpp,21
A::~A()
A::~A()
A::~A()
文件打开失败!
注: 子类的异常处理应该写在基类处理的前面,否则会发生向上造型提前捕获异常。(catch子句根据异常的类型自上而下顺序匹配,而不是最匹优配,所以对子类类型的异常捕获不要放在对基类类型异常捕获的后面,否则前者将被后者提前截取。)
04exception.cpp
#include <iostream>
using namespace std;
class ErrorA{};
class ErrorB:public ErrorA{};
int main(void){
try{
//...
throw ErrorA();
throw ErrorB();
//...
}
catch(ErrorB& ex){
cout << "捕获到ErrorB的异常!" << endl;
return -1;
}
catch(ErrorA& ex){
cout << "捕获到ErrorA的异常!" << endl;
return -1;
}
return 0;
}
5、函数异常说明
- 1)定义:
void func(形参表) throw(异常类型表){//函数体}
- 2)函数的异常说明是一种承诺,表示该函数所抛出的异常不会超出所说明的范围,如果抛出了异常以外的类型,该异常无法正常捕获,而会被系统捕获终止进程。
- 3)函数异常说明的两种极端形式
- 不写异常说明,表示可以抛出任何异常;
- 空异常说明,throw(),表示不会抛出任何异常。
- 4)函数的声明和定义如果分开写,要保证异常说明一致。
05exception.cpp
#include <iostream>
using namespace std;
class FileError{};
class MemoryError{};
//函数的声明
void func(void) throw(int, FileError, MemoryError);
//函数的定义
void func(void) throw(int, FileError, MemoryError){
//...
throw FileError();
}
int main(void){
try{
func();
}
catch(int ex){
cout << "int类型异常" << endl;
return -1;
}
catch(FileError& ex){
cout << "FileError类型异常" << endl;
return -1;
}
catch(MemoryError& ex){
cout << "MemoryError类型异常" << endl;
return -1;
}
return 0;
}
- 5)如果基类中虚函数带有异常说明,那么该函数在子类中的覆盖版本不能说明比基类抛出更多的异常,否则将会因为“放松throw限定”导致编译失败。
06exception.cpp
#include <iostream>
using namespace std;
class Base{
public:
virtual void func(void)throw(int, char){}
virtual ~Base(void) throw(){}
};
class Derived:public Base{
void func(void) throw(int,char){}
//void func(void) throw(int){}//ok
//void func(void) throw(int,char,double){}//error
~Derived(void) throw(){}
//~Derived(void){}//error
};
int main(void){
return 0;
}
6、标准异常类:exception
class exception{
public:
exception() throw() {}
virtual ~exception() throw() {}
virtual const char* what() const throw();
};
07exception.cpp
#include <iostream>
using namespace std;
class FileError:public exception{
public:
~FileError(void)throw(){};
const char* what(void) const throw(){
cout << "针对文件错误的处理" << endl;
return "FileError";
}
};
class MemoryError:public exception{
public:
~MemoryError(void)throw(){};
const char* what(void) const throw(){
cout << "针对内存错误的处理" << endl;
return "MemoryError";
}
};
void func() throw(FileError, MemoryError){
throw FileError();
//throw MemoryError();
}
int main(void){
try{
//char* p = new char[0xffffffff];
func();
}
catch(exception& ex){
cout << ex.what() << endl;
}
return 0;
}
7、构造和析构函数中的异常
- 1)构造函数可以抛出异常,但是对象将会被不完整构造,这样对象析构函数无法正常被执行;所以在构造函数抛出异常之前,需要手动地销毁在异常产生之前所分配的动态资源。
- 2)析构函数不要抛出异常。
08exception.cpp
#include <iostream>
#include <cstdio>
using namespace std;
class A{
public:
A(void){
cout << "A::A()" << endl;
}
~A(void){
cout << "A::~A()" << endl;
}
Review cpp day04