C++中的異常


一,異常的推演

1.函數與異常

  平時我們在函數中出現異常情況時通常通過return終止函數並返回一個值,然后在函數上層來獲取值並判斷是什么異常情況。因為函數是棧結構的,所以return的時候是通過棧結構逐步往上的,不能夠跨函數直接拋出,不方便。所以C++推出了異常機制,通過異常機制我們可以輕松的捕獲要出現的異常。

2.C++中異常的基本演示

# include<iostream>
using namespace std;

/* 定義求商函數,如果除數為0,拋出double類型異常 */
double div(double d1, double d2)
{
    if (d2 == 0)
    {
        throw d2;
    }
    return d1 / d2;
}

int main()
{
    /* try...catch語句來捕獲異常 */
    try
    {
        double result = div(1.02, 0.0);
    }
    catch (double e)
    {
        /* C++中的異常嚴格要求類型匹配,即拋出什么的異常就catch什么類型的異常 */
        cout << e << "不能作除數" << endl;
    }
    catch (...)
    {
        cout << "未知異常" << endl;
    }

    return 0;
}

 3.C++中異常的總結

  • 異常的捕捉嚴格匹配數據類型,不支持類型自動轉換,throw的是int類型則catch的必須是int類型否則不會匹配。
  • 一般我們在異常最后加入catch(...)這樣能夠捕獲任意異常。

二,自定義異常類

1.異常類

  按照面向對象的思維,我們的異常也應該是一個對象,所以在拋出異常的時候,我們通常自定義一個異常類,然后把異常信息放入異常類中,然后在捕捉到異常對象的時候,再調用對象的方法,打印出異常的信息。

2.異常類代碼演示

# define _CRT_SECURE_NO_WARNINGS
# include<iostream>
using namespace std;

/* 自定義異常類 */
class MyException
{
private:
    char * content;
public:
    /* 異常類構造函數 */
    MyException(const char * content)
    {
        this->content = new char[strlen(content) + 1];
        strcpy(this->content, content);
        cout << "異常類有參構造函數執行" << endl;
    }
    /* 異常類拷貝構造函數 */
    MyException(const MyException& me)
    {
        this->content = new char[strlen(me.content) + 1];
        strcpy(this->content, me.content);
        cout << "異常類拷貝構造函數執行" << endl;
    }
    /* 異常類析構函數 */
    ~MyException()
    {
        if (this->content != NULL)
        {
            delete[] this->content;
            this->content = NULL;
        }
        cout << "異常類的析構函數執行" << endl;
    }
    /* 異常類拋出異常信息 */
    void toString()
    {
        cout << this->content << endl;
    }
};

/* 定義測試異常的函數 */
double divide(double d1, double d2)
{
    if (d2 == 0)
    {
        throw MyException("除數不能為0");
        //throw new MyException("除數不能為0");
    }
    return d1 / d2;
}

int main()
{
    try
    {
        double result = divide(1, 0);
        cout << "result = " << result << endl;
    }
    catch (MyException e)
    {
        // catch的異常是元素類型,執行的是拷貝構造函數,存在兩個異常對象,釋放兩個異常對象,不合理
        e.toString();
    }
    catch (MyException * e)
    {
        // catch的異常是指針類型,必須我們手動調用delete方法才能調用析構函數,不合理
        e->toString();
        delete e;
    }
    catch (MyException& e)
    {
        // catch的是引用類型,是原先拋出的對象,會自動執行析構函數,我們使用引用來接收拋出的異常對象
        e.toString();
    }
    catch (...)
    {
        cout << "未知異常" << endl;
    }

    return 0;
}

3.自定義異常類總結

  • 拋出異常對象通常用引用的方式來catch這個對象,如果是元素catch異常對象則會執行拷貝構造函數,創建兩個重復異常對象並釋放兩次對象,所以說不合理。如果catch的是指針類型,不會自動調用該對象的析構函數必須我們手動delete,也不符合自動調用的邏輯,所以使用引用的方式來catch異常對象。

三,標准異常類

1.標准異常類

  C++中提供了標准的異常類,需要# include<exception>,標准異常類為exception,該類有個what函數,可以打印異常對象的異常信息。該what函數是虛函數,我們需要繼承exception類並重寫該what函數,在捕捉異常的時候,我們用父類的引用來接收自定義的標准異常類的子類對象(類型兼容性原則),然后打印該異常信息即可。

2.標准異常類演示

# include<iostream>
# include<exception>
using namespace std;

/* 繼承自標准異常類 */
class DivException :public exception
{
private:
    const char * ptr;
public:
    /* 構造函數接收異常信息 */
    DivException(const char * ptr)
    {
        this->ptr = ptr;
    }
    /* 重寫what函數 */ 
    virtual char const * what() const
    {
        cout << this->ptr << endl;
        return ptr;
    }
};
/* 測試異常函數 */
int divi(int a, int b)
{
    if (b == 0)
    {
        throw DivException("除數不能為0");
    }
    return a / b;
}

int main()
{
    try
    {
        divi(10, 0);
    }
    catch (exception& e)
    {
        /* 使用exception引用接收自定義的子類對象 */
        e.what();
    }
    catch (...)
    {
        cout << "未知異常" << endl;
    }

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM