- 遵循经典设计准则
- 改进的关键点
—Exception
类继承自Object
类
堆空间中创建异常对象失败后,返回NULL指针
— 新增InvalidOperationException
异常类
成员函数调用时,如果状态不正确则抛出异常
—SmartPointer
类继承自Objec
t 类
堆空间中创建智能指针对象失败后,返回NULL指针 - DTLib的开发方式和注意事项
— 迭代开发
每次完成一个小的目标,持续开发,最终打造可复用类库
— 单一继承树
所有的类都继承于Object,规范堆对象创建的行为
— 只抛异常,不处理异常
使用 THROW_EXCEPTION 抛出异常,提高可移植性。
因为可能项目里面不支持异常处理,我们选择把宏定义后面那部分给注释掉,使得我们的代码依旧照常运行,这时候觉得一开始把抛出异常设置成宏定义真是神来之笔。
— 弱耦合性
尽量不使用标准库中的类和函数,提高可移植性
SmartPointer.h
#ifndef SMARTPOINTER_H
#define SMARTPOINTER_H
#include "Object.h"
namespace DTLib
{
template <typename T>
class SmartPointer : public Object
{
T* m_pointer;
public:
SmartPointer(T* p = nullptr)
{
m_pointer = p;
}
SmartPointer(const SmartPointer<T>& obj)
{
m_pointer = obj.m_pointer;
const_cast<SmartPointer<T>&>(obj).m_pointer = nullptr;
}
T* operator->()
{
return m_pointer;
}
T& operator*()
{
return *m_pointer;
}
SmartPointer<T>& operator=(const SmartPointer<T>& obj)
{
if(this != &obj)
{
delete m_pointer;
m_pointer = obj.m_pointer;
const_cast<SmartPointer<T>&>(obj).m_pointer = nullptr;
}
return *this;
}
bool isNull()
{
return (m_pointer == nullptr);
}
T* get()
{
return m_pointer;
}
~SmartPointer()
{
delete m_pointer;
}
};
}
#endif // SMARTPOINTER_H
Exception.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 InvalidOperatorException : public Exception
{
public:
InvalidOperatorException() : Exception(0){}
InvalidOperatorException(const char* message) : Exception(message){}
InvalidOperatorException(const char* file, int line) : Exception(file, line){}
InvalidOperatorException(const char* message, const char* file, int line) : Exception(message, file, line){}
InvalidOperatorException(const InvalidOperatorException& e) : Exception(e){}
InvalidOperatorException& operator=(const InvalidOperatorException& e)
{
Exception::operator=(e);
return *this;
}
};
}
#endif // EXCEPTION_H
Object.h
#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
Exception.cpp
#include "Exception.h"
#include <cstring>
#include <cstdlib>
namespace DTLib
{
void Exception::init(const char* message, const char* file, int line)
{
m_message = strdup(message);
if(file != nullptr)
{
char sl[16] = {0};
itoa(line, sl, 10);
m_location = reinterpret_cast<char*>(malloc(strlen(file) + strlen(sl) + 2));
if(m_location != nullptr)
{
strcpy(m_location, file);
strcat(m_location, ":");
strcat(m_location, sl);
}
/*
13课的11min说明了原因
下面这个不要抛出异常。逻辑上看:父类里面抛出了一个子类的对象作为异常,就很奇怪。老爸还没诞生,先将儿子扔出去?
代码上看:子类里面会调用父类的构造函数,就会形成死循环。
*/
// else
// {
// THROW_EXCEPTION(NoEnoughMemoryException, "Exception::init");
// }
}
else
{
m_location = nullptr;
}
}
}
Exception::Exception(const char* message)
{
init(message, nullptr, 0);
}
Exception::Exception(const char* file, int line)
{
init(nullptr, 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);
}
}
Object.cpp
#include "Object.h"
#include <iostream>
#include <cstdlib>
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()
{
return malloc(size);
}
void Object::operator delete[](void* p)
{
free(p);
}
Object::~Object()
{
}
}
main.cpp
#include <iostream>
#include "SmartPointer.h"
#include "Object.h"
#include "Exception.h"
using namespace std;
using namespace DTLib;
int main()
{
SmartPointer<int>* pt = new SmartPointer<int>;
delete pt;
InvalidOperatorException* pi = new InvalidOperatorException;
delete pi ;
return 0;
}