第十一課、異常類的構建-------------狄泰軟件學院

1、自定義異常類

一、異常的類型能夠是自定義的類類型ios

二、對於類類型的匹配依舊是之上而下的嚴格匹配c++

三、賦值兼容性原則在異常匹配中依然適用安全

因此要數據結構

(1)、匹配子類異常的catch放在上部ide

(2)、匹配父類異常的catch放在下部函數

四、異常類是數據結構所依賴的「基礎設施」(現代c++庫也必然包含充要的異常類族)測試

2、一步步打造本身的異常類

一、首先是抽象類EXception的編寫,既然是抽象類,必然含有純虛函數,一般的作法都是將析構函數做爲純虛函數this

頭文件:接口定義spa

class Exception { protected: char* m_message; char* m_location; void init(const char* message, const char* file, int line); public: Exception(const char* message); Exception(const char* file, int line); Exception(const char* message, const char* file, int line); Exception(const Exception& e); Exception& operator = (const Exception& e); virtual const char* message() const; virtual const char* location() const; virtual ~Exception() = 0; };

實現文件:3d

void Exception::init(const char* message, const char* file, int line) { m_message = strdup(message);//指向的message可能在棧空間,也可能在堆空間或者全局數據去, //爲了安全,這裏先複製一份到堆空間

    if( file != NULL) { char sl[16] = {0}; itoa(line, sl, 10);//首先將行號轉化爲字符串
 m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); m_location = strcat(m_location, file); m_location = strcat(m_location, ":"); m_location = strcat(m_location, sl); } else { m_location = NULL; } } Exception::Exception(const char* message) { init(message, NULL, 0); } Exception::Exception(const char* file, int line) { init(NULL, file, line); } Exception::Exception(const char* message, const char* file, int line) { init(message, file, line); } Exception::Exception(const Exception& e) { m_message = strdup(e.m_message); m_location = strdup(e.m_location); } Exception& Exception::operator = (const Exception& e) { if( this != &e ) { free(m_message); free(m_location); m_message = strdup(e.m_message); m_location = strdup(e.m_location); } return *this; } const char* Exception::message() const { return m_message; } const char* Exception::location() const { return m_location; } Exception::~Exception() { free(m_message); free(m_location); }

          因爲構造函數的幾個重載實現方式都差很少,因此定義一個init()函數來進行初始化會方便一點。那EXception類的接口函數const char* Exception::message() const和const char* Exception::location() const爲何要定義成const屬性的呢?緣由很簡單,當有人捕捉到異常後,確定只但願看到異常是什麼樣,而不但願改變不當心改變相應的成員變量的值,那怎麼樣才能保證對象的成員變量的值不被改變?那就是將對象用const修飾使其成爲只讀對象,而const對象只能調用const的成員函數,這就是爲何將這兩個函數聲明爲const的緣由。後面作測試的時候咱們就將看到const對象調用const函數。

          可能還會有疑問的一點是析構函數不是純虛函數嗎?純虛函數不是隻聲明而不定義?這是c++的語法規定,因爲子類對象在析構時也必須調用父類的析構函數,故即便父類的析構函數定義爲純虛函數也應該實現它。

二、各類異常類的實現:繼承EXception後調用相應的父類函數便可

如計算異常類的構建(其餘的異常類只需將相應的類名換掉便可)

//計算類異常
class ArithmeticException:public Exception { public: ArithmeticException():Exception(0) {} ArithmeticException(const char* message):Exception(message) {} ArithmeticException(const char* file, int line):Exception(file, line) {} ArithmeticException(const char* message, const char* file, int line):Exception(message, file, line) {} ArithmeticException(const ArithmeticException& e): Exception(e) {} ArithmeticException& operator = (const ArithmeticException& e) { Exception::operator =(e); return *this; } };

三、至此,咱們的異常類的構建已所有完成,接下來是測試階段

爲了使用方便,咱們能夠首先定義一個宏,之後使用時使用該宏只須要填上相應的類名和拋出的信息便可

#define THROW_EXCEPTION(e,m)  (throw e(m, __FILE__, __LINE__))

測試代碼:

int main() { try { THROW_EXCEPTION(IndexOutOfBoundsException, "test"); } catch(const IndexOutOfBoundsException& e) { cout << "ArithmeticException" << endl; cout << e.message() << endl; cout << e.location() << endl; } catch(const Exception& e) { cout << "Exception" << endl; cout << e.message() << endl; cout << e.location() << endl; } return 0; }

必定要注意匹配子類異常的catch放在上部,匹配父類異常的catch放在下部。

3、完整代碼

#ifndef EXCEPTION_H #define EXCEPTION_H

namespace DTLib { #define THROW_EXCEPTION(e,m)  (throw e(m, __FILE__, __LINE__))

class Exception { protected: char* m_message; char* m_location; void init(const char* message, const char* file, int line); public: Exception(const char* message); Exception(const char* file, int line); Exception(const char* message, const char* file, int line); Exception(const Exception& e); Exception& operator = (const Exception& e); virtual const char* message() const; virtual const char* location() const; virtual ~Exception() = 0; }; //計算類異常
class ArithmeticException:public Exception { public: ArithmeticException():Exception(0) {} ArithmeticException(const char* message):Exception(message) {} ArithmeticException(const char* file, int line):Exception(file, line) {} ArithmeticException(const char* message, const char* file, int line):Exception(message, file, line) {} ArithmeticException(const ArithmeticException& e): Exception(e) {} ArithmeticException& operator = (const ArithmeticException& e) { Exception::operator =(e); return *this; } }; //空指針異常
class NullPointerException:public Exception { public: NullPointerException():Exception(0) {} NullPointerException(const char* message):Exception(message) {} NullPointerException(const char* file, int line):Exception(file, line) {} NullPointerException(const char* message, const char* file, int line):Exception(message, file, line) {} NullPointerException(const NullPointerException& e): Exception(e) {} NullPointerException& operator = (const NullPointerException& e) { Exception::operator =(e); return *this; } }; //越界異常
class IndexOutOfBoundsException:public Exception { public: IndexOutOfBoundsException():Exception(0) {} IndexOutOfBoundsException(const char* message):Exception(message) {} IndexOutOfBoundsException(const char* file, int line):Exception(file, line) {} IndexOutOfBoundsException(const char* message, const char* file, int line):Exception(message, file, line) {} IndexOutOfBoundsException(const IndexOutOfBoundsException& e): Exception(e) {} IndexOutOfBoundsException& operator = (const IndexOutOfBoundsException& e) { Exception::operator =(e); return *this; } }; //內存不足異常
class NoEnoughMemoryException:public Exception { public: NoEnoughMemoryException():Exception(0) {} NoEnoughMemoryException(const char* message):Exception(message) {} NoEnoughMemoryException(const char* file, int line):Exception(file, line) {} NoEnoughMemoryException(const char* message, const char* file, int line):Exception(message, file, line) {} NoEnoughMemoryException(const NoEnoughMemoryException& e): Exception(e) {} NoEnoughMemoryException& operator = (const NoEnoughMemoryException& e) { Exception::operator =(e); return *this; } }; //參數錯誤異常
class InvalidParameterException:public Exception { public: InvalidParameterException():Exception(0) {} InvalidParameterException(const char* message):Exception(message) {} InvalidParameterException(const char* file, int line):Exception(file, line) {} InvalidParameterException(const char* message, const char* file, int line):Exception(message, file, line) {} InvalidParameterException(const InvalidParameterException& e): Exception(e) {} InvalidParameterException& operator = (const InvalidParameterException& e) { Exception::operator =(e); return *this; } }; } #endif // EXCEPTION_H
EXception.h
#include "Exception.h" #include <cstring> #include <cstdlib>

using namespace std; namespace DTLib { void Exception::init(const char* message, const char* file, int line) { m_message = strdup(message);//指向的message可能在棧空間,也可能在堆空間或者全局數據去, //爲了安全,這裏先複製一份到堆空間

    if( file != NULL) { char sl[16] = {0}; itoa(line, sl, 10);//首先將行號轉化爲字符串
 m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2)); m_location = strcat(m_location, file); m_location = strcat(m_location, ":"); m_location = strcat(m_location, sl); } else { m_location = NULL; } } Exception::Exception(const char* message) { init(message, NULL, 0); } Exception::Exception(const char* file, int line) { init(NULL, file, line); } Exception::Exception(const char* message, const char* file, int line) { init(message, file, line); } Exception::Exception(const Exception& e) { m_message = strdup(e.m_message); m_location = strdup(e.m_location); } Exception& Exception::operator = (const Exception& e) { if( this != &e ) { free(m_message); free(m_location); m_message = strdup(e.m_message); m_location = strdup(e.m_location); } return *this; } const char* Exception::message() const { return m_message; } const char* Exception::location() const { return m_location; } Exception::~Exception() { free(m_message); free(m_location); } }
EXception.cpp
#include <iostream> #include "SmartPointer.h" #include "Exception.h"

using namespace std; using namespace DTLib; int main() { try { THROW_EXCEPTION(IndexOutOfBoundsException, "test"); } catch(const IndexOutOfBoundsException& e) { cout << "ArithmeticException" << endl; cout << e.message() << endl; cout << e.location() << endl; } catch(const Exception& e) { cout << "Exception" << endl; cout << e.message() << endl; cout << e.location() << endl; } return 0; }
main.cpp

4、小結

(1)、現代c++庫必然包含充要的異常類族

(2)、全部庫中的數據結構都依賴於異常機制

(3)、異常機制可以分離庫中代碼的正常邏輯和異常邏輯

相關文章
相關標籤/搜索