C++ 编写自己的异常类

来源:互联网 发布:淘宝首页钻展费用 编辑:程序博客网 时间:2024/05/16 00:50
编写自己的异常类有两个好处:
1)C++标准库中的异常数目有限,可以在程序中为特定的错误创建更有意义的类名称,而不是使用具有通常名称的异常类,例如runtime_error
2)可以在异常中加入自己的信息,而标准层次结构中的异常只允许设置错误字符串。例如或许想在异常中传递不同的信息。

示例为文件错误定义自己的错误层次结构,从一个泛型类FileError开始:

#pragma once#include<iostream>#include<exception>#include<string>using namespace std;class FileError :public exception{public:FileError(const string& fileIn) :mFile(fileIn) {};virtual const char* what() const noexcept override { return mMgs.c_str(); }const string& getFileName() { return mFile; }protected:void setMessage(const string &message) { mMgs = message; }private:string mFile, mMgs;};

    作为一名优秀程序员,应将FileError作为标准异常层次结构的一部分,将其作为exception的子类是恰当的。当编写exception的派生类时,需要重写what()方法,这个方法的原型已经出现过,其返回值作为一个在对象销毁之前一直有效的const char*字符串。在FileError中,这个字符串来自mMsg数据成员,在构造函数中将其设置为“”。FileError的派生类如果想给出不同的消息,就必须用不同的消息设置这个mMsg字符串。

泛型类FileError还包含文件名、访问文件名的公有方法和受保护的设置方法,以便派生类可以设置该消息。

readIntegerFile()中第一种异常情况是无法打开文件。因此,下面编写FileError的派生类FileOpenError:

#pragma once#include"FileError.h"#include<string>#include<iostream>using namespace std;class FileOpenError :public FileError{public:FileOpenError(const std::string& fileNameIn);};
FileOpenError::FileOpenError(const std::string & fileNameIn):FileError(fileNameIn){setMessage("Unable to open" + fileNameIn);}

       FileOpenError修改mMsg字符串,令其表示文件打开错误。

       readInterFile()的第二种异常情况是无法正确读取文件。对于这一异常,或许应该包含文件中发生错误的行为,以及what()返回的错误信息字符串中的文件名。下面是FileError的派生类FileReadError:

#pragma once#include<iostream>#include<string>#include"FileError.h"#include<sstream>using namespace std;class FileReadError :public FileError{public:FileReadError(const string&fileNameIn, int lineNumIn);int getLineNum() { return mLineNum; }private:int mLineNum;};

FileReadError::FileReadError(const string & fileNameIn, int lineNumIn):FileError(fileNameIn),mLineNum(lineNumIn){ostringstream ostr;ostr << "Error reading " << fileNameIn << " at line " << lineNumIn;setMessage(ostr.str());}

readIntegerFile()函数

正确设置行号,跟踪所读取的行号

#include"stdafx.h"#include<iostream>#include"FileOpenError.h"#include"FileReadError.h"#include<fstream>#include<vector>using namespace std;/**readIntegerFile()函数正确设置行号,跟踪所读取的行号*/void readIntegerFile(const string& fileName, vector<int>&dest){ifstream istr;int temp;string line;int lineNumber = 0;istr.open(fileName);if (istr.fail()){throw FileOpenError(fileName);}while (!istr.eof()){//read one line from the filegetline(istr, line);lineNumber++;//Create a string stream out of the line.istringstream lineStream(line);//Read the integers one by one and add them to the vectorwhile (lineStream >> temp){dest.push_back(temp);}if (!lineStream.eof()){//we did not reach the end of the string stream//this means that some error occurred while reading this line.//throw an exceptionthrow FileReadError(fileName, lineNumber);}}}int main(){vector<int> myInts;const string fileName = "C:/Users/Administrator/Desktop/IntegerFile.txt";try {readIntegerFile(fileName, myInts);}catch (const FileError&e) {cerr << e.what() << endl;return 1;}for (const auto element : myInts){cout << element << " ";}cout << endl;return 0;}


txt文件



输出


         编写其对象用作异常的类时,有一个诀窍。当某段代码抛出一个异常时,复制被抛出的值或者对象。也就是说,使用复制构造函数从就对象构造新对象。复制是必须的,因为原始对象在堆栈中的位置较高,可能在异常被捕获之前超出作用域(因此会被销毁,其所占的内存会被回收)。因此,如果编写的类的对象将作为异常抛出,对象必须能复制,这意味着如果动态分配了内存,必须编写析构函数、复制构造函数和赋值运算符。

       注意:作为异常抛出的对象至少按值复制一次。

       异常可能被复制多次,但只有按值(而不是按引用)捕获异常才会如此。

       注意:按引用捕获异常对象可以避免不必要的复制。


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 软考准考证丢了怎么办 面试薪资要低了怎么办 应聘等通知没有电话回复怎么办 学生信息表里的籍贯不对怎么办? 小学生信息表里的籍贯不对怎么办? 钉钉下班没打卡怎么办 如果在厂里饭卡丢了怎么办 工作上做错了事想辞职怎么办 结婚辞职怀孕感觉做错了怎么办 换新手机了钉钉怎么办 公众号申请链接无效怎么办 指纹打卡机时间调错已打卡怎么办 智慧云平台先锋讲座打不开怎么办 下雨穿套裙工装好冷怎么办 国家债务违约不要国际融资怎么办 欠钱的确还不起怎么办 生完孩孑后手发账握不死手怎么办 工作调动没啥消息怎么办 裁剪刀老是推歪怎么办 衣服上粘胶水了怎么办 衣服钻掉了有胶怎么办 衣服上贴纸掉了怎么办 裤子沾上502胶水怎么办 衣服上沾泡沫胶怎么办 衣服上面滴上502怎么办 502胶水弄衣服上怎么办 裤子上粘了胶怎么办 胶水滴在衣服上怎么办 衣服上有502胶水怎么办 衣服上面粘了胶怎么办 衣服上的胶干了怎么办 凌晨4点到火车站怎么办 运管罚款没钱交怎么办 郑州地铁票没买怎么办 遇到吸毒者拦路威胁要钱怎么办 开车遇见拦路要钱的怎么办 高速上有人拦车怎么办 马路上有人拦车怎么办 苹果手机下截软件要钱怎么办 孩子在学校问同学要钱怎么办 在学校被同学要钱怎么办