목표 : 공무원 클래스의 등급이 정해진 범위를 벗어났을 때 예외를 발생시킴으로써 CPP의 예외처리 방법에 대해 학습한다.
[Ex00: Mommy, when I grow up, I want to be a bureaucrat! 과제]
Bureaucrat
(공무원) 클래스 작성
name
grade
(1~150 사이의 int 범위): 유효하지 않은 grade면 예외처리를 해야한다.예외처리블록은 다음과 같이 catchable 해야한다.
try
{
/* do some stuff with bureaucrats */
}
catch (std::exception & e)
{
/* handle exception */
}
<<
연산자 오버로드<name>, bureaucrat grade <grade>
이번 과제에서는 CPP에서 예외 처리(exception handling)를 어떤 방법으로 하는지 학습할 수 있다. 예외를 처리한다는 것은, 예외가 발생할 만한 상황과 예외가 발생했을 때의 동작을 프로그램 구현 단계에서 미리 예상하고 있겠다는 의미다.
C에서는 조건문(if)를 통해서 예외를 처리했었지만, CPP에서는 보다 더 직관적인 문법을 제공한다. try
와 catch
구문인데, 예외가 발생할 만한 상황 을 try
코드블록에, 예외가 발생했을 때의 동작 을 catch
코드블록에 정의해두면 된다.
try
: 예외가 발생할 가능성이 있는 코드 블록. 예외가 발생하지 않는다면 try~catch문이 없는 것과 동일하게 동작하며, 예외가 발생하면 그 즉시 catch
문으로 점프한다.catch
: 내부에 정의된 예외처리를 실시하는 코드 블록.조건문은 프로그램의 논리를 위한 코드로만 사용하고, 예외를 처리할 때는 '의도치 않은 상황'과 그때의 동작에만 집중해 코드를 짤 수 있도록 프로그램 차원에서 문법을 제공하는 것이다.
그러면 개발자는 '의도치 않은 상황'이 언제 발생할 수 있을지만 생각해 보면 된다. 이번 과제에서는 공무원 클래스의 등급이 1~150 범위를 벗어날 때일 것이다.
위의 두 상황을 항상 try
코드블럭에 넣어두면, 예외가 발생했을 때 catch절로 넘어가 상황을 종료하고 정상적인 동작을 취할 수 있도록 프로그램을 잘 구현할 수 있게 된다.
try 에서 예외가 발생했을 때 어떻게 catch 절에 예외 상황을 전달할 수 있을까? 이때 사용하는 것이 throw
문이다. throw
는 try 문에서 예외를 탐색하면 throw의 변수를 catch로 전달한다.
try {
if (예외 상황) {
throw 변수명
};
};
즉 catch
는, throw에서 던진 변수를 인자로 받아 catch 내부에 정의된 예외처리를 실시하는 코드 블록이다. 이때 각 catch 절은 인자로 받은 변수의 타입에 따라 예외 상황을 다르게 처리할 수 있다.
하지만 CPP 표준에서는 throw 문의 피연산자로 std::exception
에서 파생되는 예외 타입을 사용하도록 권장하고 있다. 이 클래스에는 cpp에서 제공하는 많은 예외 타입이 이미 정의되어 있기 때문이다.
예외를 담당하는 기본 CPP제공 클래스이다. 모든 예외 처리 클래스는 이 클래스를 상속받아서 작성된다. 따라서 다형성의 원리에 의해 어떤 에러를 던지더라도, 추상클래스인 exception 클래스 로 받을 수 있다.
exception 클래스는 하나의 문자열 포인터를 반환하는 what()
이라는 가상 멤버 함수를 제공한다. 이 멤버 함수는 가상 함수이므로, exception 클래스로부터 파생된 클래스 내에서 재정의 해 원하는 문자열을 출력할 수 있도록 할 수 있다.
what
함수의 레퍼런스와 반환값은 다음과 같다. (출처)
virtual const char* what() const throw(); //(until C++11)
virtual const char* what() const noexcept; //(since C++11)
#include <exception>
class Bureaucrat
{
private:
const std::string name_;
int grade_;
public:
Bureaucrat(const std::string name, int grade);
~Bureaucrat();
class GradeTooHighException : public std::exception
{
public:
virtual const char* what() const throw();
};
};
GradeTooHighException
을 선언했다.what()
가상함수도 함께 선언한다.#include "Bureaucrat.hpp"
Bureaucrat::Bureaucrat(const std::string name, int grade) : name_(name), grade_(grade)
{
if (grade_ < 1)
throw Bureaucrat::GradeTooHighException();
}
const char* Bureaucrat::GradeTooHighException::what() const throw()
{
return ("BureaucratException: Grade too High");
}
Bureaucrat
객체 생성시 인자로 들어온 grade_
가 1보다 작을 때, exeception
클래스를 throw
한다.what()
을 오버라이딩한다. 원하는 문자열을 반환하면 된다.#include "Bureaucrat.hpp"
int main(void)
{
try
{
Bureaucrat test("test", 151);
}
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
return (0);
}
throw
할 것 같은 곳에 try
block으로 감싼다. catch
block 으로 감싼다.exception& e
는 프로그램이 던지는 에러를 받아주는 객체이다.try/catch
구문은 if
문 처럼 state가 한줄이더라도 꼭 {}
로 감싸줘야 한다.