补充的知识:
1、char * strdup(const char* s); 头文件:#include <cstring>
用途:在堆空间申请一段内存,并将指针 s 指向的内容拷贝一份放进去,然后返回堆空间的内存。例如:m_message = strdup(message),意思就是在堆空间申请一段内存,并将 message 里面的内容拷贝一份放进堆空间,m_message 指向堆空间,从而实现赋值。主要原因是不知道指针 s 指向的内容是在栈上还是在堆上。
char* itoa(int value, char *string,int radix);
2、itoa(i, buffer, 10) 头文件:#include <cstdlib>
用途:把整数转换为字符串;i 代表整型,buffer 一般指整形数组,10指的是十进制
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
int line = 10;
char str[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a'};
itoa(line, str, 10);
cout << str << endl;
return 0;
}
异常类的构建
- 异常的类型可以是自定义类型
- 对于类类型的异常的匹配依旧是自上而下严格匹配
- 赋值兼容性原则在异常匹配中依然适用(子类的异常对象可以被父类的 catch 抓住)
- 一般而言
— 匹配子类异常的 catch 放在上部
— 匹配父类异常的 catch 放在下部
异常类功能定义:
- 异常类中的接口定义
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;
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.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));
m_location = strcpy(m_location, file);
m_location = strcat(m_location, ":");
m_location = strcat(m_location, sl);
}
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);
}
}
main.cpp
#include <iostream>
#include "Exception.h"
using namespace std;
using namespace DTLib;
int main()
{
try
{
THROW_EXCEPTION(ArithmeticException, "xiebs");
}
catch (const ArithmeticException& e)
{
cout << "catch (const ArithmeticException& e)" << endl;
cout << e.message() << endl;
cout << e.location() << endl;
}
catch (const Exception& e)
{
cout << "catch (const Exception& e)" << endl;
cout << e.message() << endl;
cout << e.location() << endl;
}
return 0;
}
设计原则:在可复用代码库设计时,尽量使用面向对象技术进行架构,尽量使用异常处理机制分离正常逻辑和异常逻辑。
纯虚函数一般不需要实现,等着子类给它实现。但是无论析构函数是不是纯虚函数,就一定要给它提供实现。存在纯虚函数就是抽象类,抽象类不能生成对象。
Exception 这个类是抽象类,下面的子类都不是抽象类。因为他们都默认提供了析构函数,相当于重写了析构函数。