38_异常

异常

作用

  1. 错误处理方式,简化处理错误的代码
  2. 让函数调用者知道会出现错误

深入

C库 printf

函数使用者和函数实现者非同一人

如果有一个除法函数,使用者调用4,0程序崩了

函数实现者知道错误,但是不知道如何处理

函数使用者知道怎么处理,但是不知道什么时候错误

Int g_error = 0;

Int myDiv(int num1, int num2)

{

If(num2 == 0)

{

g_error = -1;

Return g_error;

}

If(g_error != -1)

{

g_error = 0;

Return num1 / num2;

}

语法

抛异常

效果

      1. 如果不处理,默认调用abort()函数,弹出警告,没人处理这个错误
      2. Catch类型强制匹配,不做隐示转换
      3. 定义函数的时候可以声明抛出的异常类型,用逗号分隔
      4. 不写抛出异常的关键字表示可能抛出任何类型的异常
      5. Throw()表示不会抛出任何异常
      6. Noexcept; //不抛出异常

关键字:throw

Int myDiv(int n1, int n2)

{

If(0 == n2)

{

Throw -1; //抛异常

}

Else

{

Return n1 / n2;

}

}

接收异常

效果

      1. 可以统一检查

关键字 try catch

Int main()

{

Try

{

Int ret = myDIv(-1, 0);

}

Catch(int error) //处理错误

{

Printf(“error: %d\r\n”, error);

}

Catch(double error) //处理错误

{

Printf(“error:%d\r\n”, error);

}

Catch(…) //所有类型,防止漏收异常

{

Printf(“error:..\r\n”);

}

}

设计

1.类异常取代基本数据类型,里面数据成员存放调用的函数名

基类为异常,派生类为异常类型,可以 具体到函数名、文件名、行号

Catch基类指针

2.可以继承IOS::EXCEPTION

3.构造出错不能返回值,但是可以抛出异常,出异常之前类会自动析构

4.析构不能抛异常,如果抛了会自动调用abort

5.分层设计异常找之前调用的

作业

1.定义一个异常类CException,有成员函数reason(),用来显示异常的类型。
定义一个函数fun1()触发异常,在main函数try模块调用fun1(),
在catch模块中捕获异常,观察程序的执行流程

 //Exception.h
#pragma once
#include 

class CException
{
private:
    int dividend;
    int divisor;
public:
    void reason();
};
 //Exception.cpp
#include "Exception.h"

void CException::reason()
{
    {
        std::cout << "0不能做除数!" << std::endl;
    }
}
 //test1.cpp
#include "Exception.h"

using namespace std;

float fn1(int dividend, int divisor)
{
    if (divisor == 0)
        throw "错误!";
    else
        return float(dividend) / divisor;
}

int main()
{
    CException object;
    int dividend, divisor;
    float quotient;
    cout << "请输入除数与被除数:";
    cin >> dividend >> divisor;
    try {
        quotient = fn1(dividend, divisor);
        cout << "商是:" << quotient << endl;
    }
    catch (char *exceptionstring)
    {
        cout << exceptionstring << endl;
        object.reason();
    }

    system("pause");
    return 0;
}

2.定义一个动物类,其中动物有属性身高、体重,并提供显示动物信息方法,
如果用户忘记给动物身高或者体重信息,抛异常提醒用户。

 //Animal.h
#pragma once
#include 

using namespace std;

class CAnimal
{
public:
    CAnimal(double height = 0.0, double weight = 0.0);
    ~CAnimal();
    void printAnimalInfo();
private:
    double m_dblHeight;
    double m_dblWeight;
};
 //Animal.cpp
#include "Animal.h"

CAnimal::CAnimal(double height, double weight)
{
    m_dblHeight = height;
    m_dblWeight = weight;
}

CAnimal::~CAnimal()
{
}

void CAnimal::printAnimalInfo()
{
    if (m_dblHeight == 0
        ||
        m_dblWeight == 0
        )
    {
        cout << "动物身高体重为初始值" << endl;
        throw -1;
    }
}
 //test2.cpp
#include "Animal.h"

int main()
{
    CAnimal animal;

    try
    {
        animal.printAnimalInfo();
    }
    catch (int)
    {
        cout << "error" << endl;
    }
    catch (...)
    {

    }

    system("pause");
    return 0;
}

3.编写一个三角形类,如果三条边长无法构成三角或者边长为0,抛异常提醒用户。

 //Triangle.h
#pragma once

class CTriangle
{
public:
    CTriangle(double sideOne, double sideTow, double sideThree);
    ~CTriangle();
private:
    double m_dblSideOne;
    double m_dblSideTwo;
    double m_dblSideThree;
};
 //Triangle.cpp
#include "Triangle.h"

CTriangle::CTriangle(double sideOne, double sideTwo, double sideThree)
{
    if (sideOne == 0)
    {
        throw 1;
    }
    else if (sideTwo == 0)
    {
        throw 2;
    }
    else if (sideThree == 0)
    {
        throw 3;
    }
    else if (sideOne + sideTwo <= sideThree)
    {
        throw 4;
    }
    else if (sideOne + sideThree <= sideTwo)
    {
        throw 5;
    }
    else if (sideThree + sideTwo <= sideOne)
    {
        throw 6;
    }
}

CTriangle::~CTriangle()
{
}

 //homeWork3.cpp
#include "Triangle.h"
#include 

using namespace std;

int main()
{
    try
    {
        CTriangle tri(2.0, 3.0, 5.0);
    }
    catch (int)
    {
        cout << "error" << endl;
    }
    catch (...)
    {
        cout << "error..." << endl;
    }
    
    system("pause");
    return 0;
}

4.以string类为例,在string类的构造函数中new分配内存。如果操作不成功,
则用try语句处罚一个char类型异常,用catch语句捕获该异常。

同时将异常处理机制与其它处理方式对内存内存分配失败这一异常进行处理对比,
体会异常处理的优点。

5.在第4题的基础上,重载数组下标操作符[], 使之具有判断与处理下标越界的功能

 //MyString.h
#pragma once
#include 

class CMyString
{
public:
    CMyString(const char * str = nullptr);
    ~CMyString();
    char* operator[] (const int iIndex);
private:
    char *m_pStr;
};
 //MyString.cpp
#include "MyString.h"




CMyString::CMyString(const char * str)
{
    if (str != nullptr)
    {
        m_pStr = new char[strlen(str) + 1];

        if (m_pStr == nullptr)  //如果申请失败则抛出异常
        {
            throw "new heap error";
        }

        strcpy(m_pStr, str);
    }
}

CMyString::~CMyString()
{
    if (m_pStr != nullptr)
    {
        delete[] m_pStr;
    }
}

char* CMyString::operator[](const int iIndex)
{
    int iStrLen = strlen(m_pStr);
    if (iIndex > iStrLen)
    {
        throw "Index out of string";
    }
    else
    {
        return (m_pStr + iIndex);
    }
}
 //homeWork4.cpp
#include "MyString.h"
#include 

using namespace std;

void main()
{
    try
    {
        CMyString str("abcd");
        cout << str[3] << endl;
    }
    catch (const char *error)
    {
        cout << error << endl;
    }
    
    system("pause");
}
0 条评论
发表一条评论