C++的类型转换与异常处理

一 名称和语法
1 C语言风格:不管什么类型的转换统统是:
TYPE b = (TYPE)a;
2 C++风格:
1)static_cast,静态类型转换。如int转换成char
2)reinterpreter_cast,重新解释类型
3) dynamic_cast,命名上理解是动态类型转换。如子类和父类之间的多态类型转换,运行时进行类型识别,把父类转换成子类。
4)const_cast,字面上理解就是去const属性

void main01()
{
double dpi = 3.1415926;
int num1 = (int)dpi; //C类型转换
int num2 = static_cast<int>(dpi); //静态类型转换  编译的时c++编译器会做类型检查
int num3 = dpi; //c语言中 隐式类型转换的地方 均可使用 static_cast<>() 进行类型转换

char *p1 = "hello...itcast ";
int *p2 = NULL;
//p2 = static_cast<int*>(p1); // 使用static_cast, 编译器编译时,会做类型检查 若有错误 提示错误

p2 = reinterpret_cast<int *>(p1); //若不同类型之间,进行强制类型转换,用reinterpret_cast<>() 进行重新解释

cout << "p1:" << p1 << endl; //%s指针指向的内存空间
cout <<"p2" << p2 << endl; //%d  指针首地址

//总结:通过 reinterpret_cast<>() 和 static_cast<>()把C语言的强制类型转换 都覆盖了..
cout<<"hello..."<<endl;
system("pause");
return ;

class Animal
{
public:
virtual void cry() = 0;
};

class Dog : public Animal
{
public:
virtual void cry()
{
    cout << "汪汪" << endl;
}
void doHome()
{
    cout << "看家" << endl;
}
};

class Cat : public Animal
{
public:
virtual void cry()
{
    cout << "喵喵" << endl;
}
void doThing()
{
    cout << "抓老鼠" << endl;
}
};

void playObj(Animal *base)
{
base->cry(); // 1有继承 2虚函数重写 3 父类指针 指向子类对象  ==>多态
 //需求:在这里能识别子类对象
// dynamic_cast 运行时类型识别  RIIT

Dog *pDog = dynamic_cast<Dog *>(base);
if (pDog != NULL)//转换失败返回NULL
{
    pDog->doHome(); //让够 做自己 特有的工作 
}

Cat *pCat = dynamic_cast<Cat *>(base);  //父类对象 ===> 子类对象 
                                        //向下转型  
                                        //把老子 转成 小子 
if (pCat != NULL)
{
    pCat->doThing();  //让够 做自己 特有的工作 
}
}

void main()
{
Dog d1;
Cat c1;
Animal *pBase = NULL;
pBase = &d1;

playObj(&d1);
playObj(&c1);
system("pause");
}

#include <iostream>
using namespace std;

//const char *p 的const修饰 让p指向的内存空间 变成只读属性
void printBuf(const char *  p)
{
p1 = const_cast<char *>(p);//由const char * 转换成char*
p1[0] = 'Z' ;  //通过p1 去修改了内存空间
cout << p << endl;
}

void main()
{
char buf[] = "aaaaaaaaafffffddd";
char *myp = "aaaaaaaaafffffddd";//此时*myp指向的内存空间时常量,不可修改。
 //程序员 要确保 p所指向的内存空间 确实能修改 ;如果不能修改会带来灾难性后果
//printBuf (buf);
printBuf (myp);
system("pause");
}

二 异常处理
1 基本思想
1) C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中
2)异常是专门针对抽象编程中的一系列错误处理的
3)异常超脱于函数机制,决定了其对函数的跨越式回跳。
4)异常跨越函数

2 基本语法
1)思想
a)若有异常则通过throw操作创建一个异常对象并抛掷。
b)将可能抛出异常的程序段嵌在try块之中。控制通过正常的顺序执行到达try语句,然后执行try块内的保护段。
c)如果在保护段执行期间没有引起异常,那么跟在try块后的catch子句就不执行。程序从try块后跟随的最后一个catch子句后面的语句继续执行下去。
d)catch子句按其在try块后出现的顺序被检查。匹配的catch子句将捕获并处理异常(或继续抛掷异常)。
e)如果匹配的处理器未找到,则运行函数terminate将被自动调用,其缺省功能是调用abort终止程序。(程序down)
f)处理不了的异常,可以在catch的最后一个分支,使用throw语法,向上扔。
g)异常机制与函数机制互不干涉,但捕捉的方式是基于类型匹配。
捕捉相当于函数返回类型的匹配,而不是函数参数的匹配,所以捕捉不用考虑一个抛掷中的多种数据类型匹配问题
h)异常捕捉严格按照类型匹配

int divide(int x, int y ) //抛异常
{ 
     if (y ==0) 
     { 
               throw x; //如果执行了抛出,则后面的代码不再执行
     } 
     return x/y; 
} 
void main() //接异常
{ 
     try 
     { 
               cout << "8/2 = " << divide(8, 2) << endl;  ///调用
               cout << "10/0 =" << divide(10, 0) << endl; 
     } 
     catch (int e) //捕捉到上面的异常,同一类型
     { 
               cout << "e" << " is divided by zero!" << endl; 
     } 
     catch(...) 
     { 
               cout << "其他未知异常" << endl; 
     } 
     cout << "ok" << endl; 
     system("pause"); 
     return ; 
}

三 栈解旋(unwinding)
1 定义:异常被抛出后,从进入try块起,到异常被抛掷前,这期间在栈上的构造的所有对象,都会被自动析构。析构的顺序与构造的顺序相反。这一过程称为栈的解旋(unwinding)。

#include <iostream>
using namespace std;
class Test3
{
public:
Test3(int a=0, int b=0)
{
    this->a = a;
    this->b = b;
    cout << "构造函数do \n";
}
~Test3()
{
    cout << "析构函数do \n";
}
private:
int a;
int b;
};

void myDivide() throw (int, char, char *)
{
Test3 t1(1, 2), t2(3, 4);
cout << "myDivide ...要发生异常\n" ;

throw 1;
}

void main()
{
try
{
    myDivide();
}
catch (int a)
{
    cout << "int类型 异常\n" ;
}

catch (...)
{
    cout << " 未知 异常\n" ;
}
cout<<"hello..."<<endl;
system("pause");
return ;
}

四异常接口声明
1 为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如: void func() throw (A, B, C , D); //函数func()能够且只能抛出类型A B C D及其子类型的异常。
2 如果在函数声明中没有包含异常接口声明,则此函数可以抛掷任何类型的异常,例如:void func();
3 一个不抛掷任何类型异常的函数可以声明为:
void func() throw();
4 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,unexpected函数会被调用,该函数默认行为调用terminate函数中止程序


五 异常类型及生命周期
1 接受元素时使用异常变量,则进行拷贝构造
2 使用引用的话,catch的是throw的那个对象
3 指针和引用/元素可同时出现,但引用和元素不能同时现如果是指针必须throw的是一个地址(new 申请内存)

结论:用引用是最好的


六 标准程序库异常

C++标准提供了一组标准异常类,这些类以基类exception开始,
标准程序库抛出的所有异常,都派生于该基类。

1 案例

// out_of_range
#include "iostream"
using namespace std;
#include <stdexcept> 
#include "string"

// out_of_range
class Teacher
{
public:
Teacher(int age)
{
    if (age > 100)
    {
        string  s = "年龄太大";
        throw out_of_range(s);
    }
    this->age = age;
}
protected:
private:
int age;
};

void main61()
{
try
{
    Teacher t1(102);
}
catch (out_of_range e)
{

    cout << e.what() << endl;
}

exception e;
system("pause");
}

class MyException : public exception
{
public:
MyException(const char *p)
{
    this->m_p = p;
}

virtual const char *  what()
{
    cout << "MyException: 类型" << m_p << endl;
    return m_p;
}
protected:
private:
const char *m_p;
};

void testMyExcept()
{
throw MyException("函数异常");
}
void main()
{

try
{
    testMyExcept();
}
catch (MyException & e)
{
    e.what();
}
catch (...)
{
    cout << "未知 类型 " << endl;
}

system("pause");
}

猜你喜欢

转载自blog.csdn.net/weixin_40878579/article/details/81462427
今日推荐