第十三课、类族的结构进化-------------------狄泰软件学院

一、遵循经典设计原则

DTLib中的所有类位于单一继承树

IvalidOperationEXception是新增的异常类,描述某些成员函数在状态不对的时候被抛出

二、改进的关键点

1、EXception类继承自Object类:堆空间中创建异常对象失败时,返回NULL指针,用的是自己的new版本

更改:

2、新增IvalidOperationEXception异常类:成员函数调用时,如果状态不正确则抛出该异常

增加:

//非法操作异常
class IvalidOperationEXception:public Exception
{
public:
    IvalidOperationEXception():Exception(0) {}
    IvalidOperationEXception(const char* message):Exception(message) {}
    IvalidOperationEXception(const char* file, int line):Exception(file, line) {}
    IvalidOperationEXception(const char* message, const char* file, int line):Exception(message, file, line) {}
    IvalidOperationEXception(const IvalidOperationEXception& e): Exception(e) {}
    IvalidOperationEXception& operator = (const IvalidOperationEXception& e)
    {
        Exception::operator =(e);
        return *this;
    }
};

3、SmartPointer类继承自Object类:堆空间中创建智能指针对象失败时,返回NULL指针

更改:

注:前面课程的代码还有一些不完美

在EXception.cpp中修改init()函数,判断申请内存是否成功

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

        if( m_location !=NULL )
        {
            m_location = strcat(m_location, file);
            m_location = strcat(m_location, ":");
            m_location = strcat(m_location, sl);
        }

    }
    else
    {
        m_location = NULL;
    }
}

但是一定要注意判断语句的else分支中不能抛出内存不足的异常,原因可以从下面两个方面分析

(1)、站在一个高的角度看,内存不足的异常类是继承自抽象的异常父类,老爸还没存生就抛出儿子肯定是非法的

(2)、站在代码的角度看,构建对象的会先调用父类的构造函数,肯定又会进入到init()函数,最终会造成死循环

所以说最好的办法就是省去else语句。

三、第一阶段完整代码

#ifndef OBJECT_H
#define OBJECT_H

namespace DTLib
{

class Object
{
public:
    void* operator new (unsigned int size) throw();
    void operator delete(void* p);

    void* operator new[] (unsigned int size) throw();
    void operator delete[] (void* p);

    virtual ~Object() = 0;
};

}


#endif // OBJECT_H
Object.h
#include "Object.h"
#include <cstdlib>
#include <iostream>

using namespace std;

namespace DTLib
{

void* Object::operator new (unsigned int size) throw()
{
    cout << "Object::operator new:" << size << endl;
    return malloc(size);
}

void Object::operator delete(void* p)
{
    cout << "Object::operator delete" << p << endl;
    free(p);
}

void* Object::operator new[] (unsigned int size) throw()
{
    cout << "Object::operator new[]" << endl;
    return malloc(size);
}

void Object::operator delete[] (void* p)
{
    cout << "Object::operator delete[]" << endl;
    free(p);
}

Object::~Object()
{

}

}
Object.cpp
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#include "Object.h"

namespace DTLib
{
template <typename T>
class SmartPoiter : public Object
{
protected:
    T* m_pointer;
public:
    SmartPoiter(T* p = NULL)
    {
        m_pointer = p;
    }

    SmartPoiter(const SmartPoiter<T>& obj)
    {
        m_pointer = obj.m_pointer;
        const_cast<SmartPoiter<T>&>(obj).m_pointer = NULL;
    }

    SmartPoiter<T>& operator = (const SmartPoiter<T>& obj)
    {
        if( this != &obj )
        {
            delete m_pointer;
            m_pointer = obj.m_pointer;
            const_cast<SmartPoiter<T>&>(obj).m_pointer = NULL;
        }

        return *this;
    }

    T* operator -> ()
    {
        return m_pointer;
    }

    T& operator * ()
    {
        return *m_pointer;
    }

    bool isNull()
    {
        return (m_pointer == NULL);
    }

    T* get()
    {
        return m_pointer;
    }

    ~SmartPoiter()
    {
        delete m_pointer;
    }
};
}

#endif // SMARTPOINTER_H
SmartPoiter.h
#ifndef EXCEPTION_H
#define EXCEPTION_H

#include "Object.h"

namespace DTLib
{

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

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

//非法操作异常
class IvalidOperationEXception:public Exception
{
public:
    IvalidOperationEXception():Exception(0) {}
    IvalidOperationEXception(const char* message):Exception(message) {}
    IvalidOperationEXception(const char* file, int line):Exception(file, line) {}
    IvalidOperationEXception(const char* message, const char* file, int line):Exception(message, file, line) {}
    IvalidOperationEXception(const IvalidOperationEXception& e): Exception(e) {}
    IvalidOperationEXception& operator = (const IvalidOperationEXception& 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));

        if( m_location !=NULL )
        {
            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 "Object.h"
#include "Exception.h"
#include "SmartPointer.h"

using namespace std;
using namespace DTLib;



int main()
{
    IvalidOperationEXception* p = new IvalidOperationEXception();
    delete p;

    SmartPoiter<int>* s = new SmartPoiter<int>();
    delete s;


    return 0;
}
main.cpp

四、DTLib的开发方式和注意事项

1、迭代开发:每次完成一个小目标,持续开发,最终打造可复用类库

2、单一继承树:所有类都继承自Object,规范堆空间创建时的行为

3、只抛异常,不处理异常:使用THROW_EXCEPTION抛出的异常,提高可移植性

4、若耦合性:尽量不使用标准库中的类和函数,提高可移植性

注:在一些老编译器中,可能不支持异常处理,我们可以将宏

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

修改为

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

这样,抛出异常的语句就形同虚设了,相当于没有抛出一样,增加了可移植性。

五、第一阶段学习总结

1、数据结构与算法之间的关系

2、算法效率的度量方法

3、DTLib的基础设施

(1)、顶层父类

(2)、智能指针

(3)、异常类

posted @ 2017-05-08 21:18  lgc202  阅读(625)  评论(0编辑  收藏  举报