zoukankan      html  css  js  c++  java
  • 第十一课、异常类的构建-------------狄泰软件学院

    一、自定义异常类

    1、异常的类型可以是自定义的类类型

    2、对于类类型的匹配依旧是之上而下的严格匹配

    3、赋值兼容性原则在异常匹配中依然适用

    所以要

    (1)、匹配子类异常的catch放在上部

    (2)、匹配父类异常的catch放在下部

    4、异常类是数据结构所依赖的“基础设施”(现代c++库也必然包含充要的异常类族)

    二、一步步打造自己的异常类

    1、首先是抽象类EXception的编写,既然是抽象类,必然含有纯虚函数,通常的做法都是将析构函数作为纯虚函数

    头文件:接口定义

    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;
    };

    实现文件:

    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++的语法规定,由于子类对象在析构时也必须调用父类的析构函数,故即使父类的析构函数定义为纯虚函数也应该实现它。

    2、各种异常类的实现:继承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;
        }
    };

    3、至此,我们的异常类的构建已全部完成,接下来是测试阶段

    为了使用方便,我们可以首先定义一个宏,以后使用时使用该宏只需要填上相应的类名和抛出的信息即可

    #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放在下部。

    三、完整代码

    #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

    四、小结

    (1)、现代c++库必然包含充要的异常类族

    (2)、所有库中的数据结构都依赖于异常机制

    (3)、异常机制能够分离库中代码的正常逻辑和异常逻辑

  • 相关阅读:
    我的openwrt学习笔记(四):OpenWrt源码下载
    算法系列之“汉若塔”
    尖峰在线Oracle OCM实战 --开创国内Dtrace先河!
    Android开发屏幕适配知识点
    【cocos2d-js官方文档】十九、Cocos2d-JS单文件引擎使用指引
    PHP重载
    作为一个在城市打拼的人。
    关于马云最帅的照片是哪一张?!你们感受下!哈哈哈哈!(10P)
    Banana PI (香蕉派) 安装 ubuntu-core-14 最小核心的操作步骤
    (转载)偏序集的Dilworth定理学习
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6826449.html
Copyright © 2011-2022 走看看