• 第11课 异常类构建


    1. 异常类构建

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

    (2)对于类类型异常的匹配依旧是至上而下严格匹配

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

    (4)一般而言,匹配子类异常的catch放在上部,匹配父类异常的catch放在下部

    (5)现代C++库必然包含充要的异常类族

    2. DTLib异常类功能定义和类图

    (1)类图结构

     

    (2)功能定义

    异常类

    功能描述

    ArithmeticException

    计算异常

    NullPointerException

    空指针异常

    IndexOutOfBoundsException

    越界异常

    NotEnoughMemoryException

    内存不足异常

    InvalidParameterException

    参数错误异常

    (3)设计原则:在可复用代码库设计时,尽量使用面向对象技术进行架构,尽量使用异常处理机分离正常逻辑异常逻辑

    (4)异常类中的接口定义

    class Exception
    {
    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;    
    };

    【编程实验】创建异常类族

    //Exception.h

    #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;
    
        //注意:
        //(1)析构函数是较为特殊的函数,一旦定义了析构函数,不管这个函数是不是纯虚函数,就
        //必须提供实现。因为,对象在销毁时,最后都会调用父类的析构函数。如果父类不提供实现,
        //当对象销毁过程中调用到父类析构函数时,就找不到析构函数,也就不知该如何析构下去。
        //因此,尽管这里将析构函数声明为纯虚函数,但Exception类仍提供析构函数的实现。以便
        //最后正确释放掉m_message和m_location所指的堆空间.
        //(2)此外,声明为纯虚函数,可以让该类只能作为接口使用,而且也强迫子类必须
        //提供析构函数的实现。
        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 NotEnoughMemoryException: public Exception
    {
    public:
        NotEnoughMemoryException():Exception(0){}
        NotEnoughMemoryException(const char* message):Exception(message){}
        NotEnoughMemoryException(const char*file, int line):Exception(file, line){}
        NotEnoughMemoryException(const char *message, const char* file, int line):Exception(message, file, line){}
    
        NotEnoughMemoryException(const NotEnoughMemoryException& e): Exception(e){}
        NotEnoughMemoryException& operator=(const NotEnoughMemoryException& 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.cpp

    #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);//将整数line转为字符串,其中的10表示转换为十进制格式
    
            //m_location的格式为:file:line;
            m_location = static_cast<char*>(malloc(strlen(file) + strlen(sl) + 2));
            m_location = strcpy(m_location, file);
            m_location = strcat(m_location, ":");
            m_location = strcat(m_location, sl);
        }
    }
    
    //构造函数
    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);
    }
    
    }

    //main.cpp

    #include <iostream>
    #include "Exception.h"
    using namespace std;
    using namespace DTLib;
    
    int main()
    {
        try
        {
           THROW_EXCEPTION(ArithmeticException, "test");
    
        }catch(const ArithmeticException& e){ //子类放catch前面
            cout << "catch(const ArithmeticException& e)" << endl;
            cout << e.message() << endl;
            cout << e.location() << endl;
    
        }catch(const Exception& e){     //父类放catch后面
            cout << "catch(const Exception& e)" << endl;
            cout << e.message() << endl;
            cout << e.location() << endl;
        }
    
        return 0;
    }

    3. 小结

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

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

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

  • 相关阅读:
    MATLAB 模板匹配
    ACDSee15 教你如何轻松在图片上画圈圈、画箭头、写注释
    Qt 显示一个窗体,show()函数和exec()函数有什么区别?
    Qt 将窗体变为顶层窗体(activateWindow(); 和 raise() )
    Qt QSS样式化 菜单Qmenu&QAction
    Qt 获取文件夹中的文件夹名字
    Qt 删除文件夹或者文件
    欧洲终于承认“工业4.0”失败,互联网经济严重落后中美
    深入浅出数据结构
    浅谈城市大脑与智慧城市发展趋势
  • 原文地址:https://www.cnblogs.com/5iedu/p/6748428.html
Copyright © 2020-2023  润新知