CPP Module 05

hhkim·2022년 6월 12일
0

42cursus

목록 보기
14/20
post-thumbnail

ex00 - Mommy, when I grow up, I want to be a bureaucrat!

개념

예외 처리

  • throw 문으로 예외를 던지고 try ~ catch로 받기
  • throw 다음 문장들은 실행되지 않음
  • 함수를 빠져나가면서 스택에 생성된 객체를 자동으로 소멸시켜줌 (스택 풀기, stack unwinding)
    • 힙에 할당된 메모리는 수동으로 해제해야 함

<exception> 라이브러리의 std::exception 클래스

https://ansohxxn.github.io/cpp/chapter14-4/

class exception {
public:
  exception () throw();
  exception (const exception&) throw();
  exception& operator= (const exception&) throw();
  virtual ~exception() throw();
  virtual const char* what() const throw();
}
  • 모든 에러들은 이 클래스를 상속받아 구현되어 있음
  • <stdexcept>에 이미 정의된 에러를 사용할 수도 있음
  • 직접 상속받아 사용자 정의 예외 클래스를 만들 수도 있음
    • : public std::exception으로 상속받고 what() 오버라이딩
      👉 const char *를 리턴하기 때문에 std::string을 리턴하면 안 됨! (보통 리터럴 사용)
// exception::what
#include <iostream>       // std::cout
#include <exception>      // std::exception

struct ooops : std::exception {
  const char* what() const throw() {return "Ooops!\n";}
};

int main () {
  try {
      throw ooops();
  } catch (std::exception& ex) {
      std::cout << ex.what();
  }
  return 0;
}

예외 클래스

예외 상황을 처리할 때 필요한 변수나 함수를 멤버로 가진 클래스

  • 클래스 내부에 예외 클래스를 선언해서 클래스 동작에 대한 예외 처리를 할 수 있음 (예외의 캡슐화)
    👉 클래스 스스로 예외처리를 할 수 있어서 안전하고 재사용성이 높음

구현

예외 클래스는 Orthdox Canonical Form을 지키지 않아도 됨

Bureaucrat 클래스

  • const name: 이름
  • grade: 등급 1 ~ 150 (1이 가장 높음)
  • 유효하지 않은 등급으로 생성하는 경우 예외를 던져야 함
    • Bureaucrat::GradeTooHighException
    • Bureaucrat::GradeTooLowException
  • 게터 getName(), getGrade()
  • 등급을 올리고 낮추는 멤버 함수 2개 (올리면 1 가까이, 내리면 150 가까이)
    • 유효하지 않은 등급이 될 경우 생성자와 같은 예외 던지기
  • 던진 예외는 try ~ catch로 받을 수 있어야 함
try
{
	/* do some stuff with bureaucrats */
}
catch (std::exception &e)
{
	/* handle exception */
}
  • 삽입 연산자(<<)를 오버로딩해서 아래와 같은 문구를 출력
<name>, bureaucrat grade <grade>.

ex01 - Form up, maggots!

구현

Form 클래스

  • Form의 등급은 Bureaucrat의 등급과 같은 규칙을 따름
    👉 범위를 넘으면 예외를 던져야 함
    • Form::GradeTooHighException
    • Form::GradeTooLowException
  • Form의 모든 정보를 출력하도록 삽입 연산자(<<) 오버로딩

private 멤버 변수

  • const name
  • bool 사인되었는지 아닌지 (생성될 때는 false)
  • const 사인할 수 있는 등급
  • const 실행할 수 있는 등급

멤버 함수

  • 모든 멤버 변수에 대한 게터
  • beSigned()
    • Bureaucrat을 인자로 받음
    • 인자로 받은 객체의 등급이 요구되는 것보다 같거나 높으면 폼의 signed 상태를 바꿈
    • 등급이 낮으면 Form::GradeTooLowException 예외 던지기

Bureaucat 클래스

  • 멤버 함수 signForm() 추가
  • 폼에 사인을 받으면 <bureaucrat> signed <form> 출력
    • 아니면 <bureaucrat> couldn’t sign <form> because <reason>. 출력

ex02 - No, you need form 28B, not 28C...

개념

랜덤값 구하기

  • <cstdlib>srand()rand() 이용
  • 프로그램 초기에 srand()로 시드값을 초기화하지 않으면 1로 고정이 되고, 터미널을 새로 시작할 때까지 난수 범위가 고정됨
  • 일반적으로 프로그램을 실행할 때마다 새로운 값을 받으려면 시드를 현재 시각으로 초기화
    (<ctime>time() 활용)
  • 랜덤값의 범위가 크기 때문에 (최소 32767) 나머지 연산자로 범위를 한정함
int main ()
{
  int iSecret;

  /* initialize random seed: */
  srand (time(NULL));

  /* generate secret number between 1 and 10: */
  iSecret = rand() % 10 + 1;

  ...
  return 0;
}

구현

  • Form 상속
  • 기반 클래스 Form은 추상 클래스여야 함. Form의 모든 멤버 변수는 그대로 private
  • 아래 자식 클래스들은 모두 생성자로 form의 타겟을 인자로 받음
    • 예를 들어 관목을 집에 심고 싶으면 ShrubberyCreationForm의 인자로 home을 보냄

ShrubberyCreationForm 클래스

  • sign: 145, exec: 137
  • 현재 디렉토리에 <target>_shrubbery라는 파일을 생성하고 거기에 ASCII tree를 출력

RobotomyRequestForm 클래스

  • sign: 72, exec: 45
  • 드릴 소리 출력
  • 50% 확률로 성공 시 target이 획일화(robotomized)되었다고 출력
    • 아니면 실패했다고 출력

Makes some drilling noises. Then, informs that <target> has been robotomized
successfully 50% of the time. Otherwise, informs that the robotomy failed.

PresidentialPardonForm 클래스

  • sign: 25, exec: 5
  • target이 Zaphod Beeblebrox에 의해 사면(pardoned)되었다고 출력

Form 클래스

  • 멤버 함수 execute(Bureaucrat const & executor) const 추가
    • 자식 클래스의 액션을 수행할 수 있도록 구현 (자식에서 구현하든 부모에서 구현하든 마음대로)
    • 폼이 사인되어 있는지와 실행하려는 Bureaucat의 등급이 exec보다 같거나 높은지 검사
    • 그렇지 않으면 적절한 예외 던지기

Bureaucat 클래스

  • 멤버 함수 executeForm(Form const & form) 추가
    • 폼을 실행
    • 성공 시 <bureaucrat> executed <form> 출력
    • 실패 시 에러 메시지 출력

ex03 - At least this beats coffee-making

구현

Intern 클래스

  • 이름, 등급, 특징 없음 (멤버 변수 없음)
  • 멤버 함수 makeForm()
    • 문자열 두 개를 인자로 받음: 첫 번째는 폼의 이름, 두 번째는 폼의 타겟
    • 해당 폼에 대한 포인터를 반환
    • Intern creates <form> 출력
    • 해당 폼이 존재하지 않는 경우 에러 메시지 출력
  • if / elseif / else 구문 사용하지 말 것
    👉 module 01처럼 함수 포인터 사용해야 할 듯
  • 예시 코드
{
  Intern someRandomIntern;
  Form* rrf;

  rrf = someRandomIntern.makeForm("robotomy request", "Bender");
}

0개의 댓글