浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第11课 异常类构建

Posted on 2017-04-22 17:27  浅墨浓香  阅读(291)  评论(0编辑  收藏  举报

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\0;
        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)异常机制能够分离库中代码的正常逻辑异常逻辑