예외상황과 예외처리의 이해
문법적 오류가 아닌, 프로그램 논리에 맞지 않은 오류를 뜻한다. [프로그램 실행중 발생문제]
발생 -> 발견 -> 처리
#include<iostream>
using namespace std;
int main_1(void)
{
int num1, num2;
cout << "두 개의 숫자 입력: ";
cin >> num1 >> num2;
cout << "나눗셈의 몫: " << num1 / num2 << endl;
cout << "나눗셈의 나머지: " << num1 % num2 << endl;
return 0;
}
num2가 0이 입력되는 경우 논리 오류 발생
#include<iostream>
using namespace std;
int main_1(void)
{
int num1, num2;
cout << "두 개의 숫자 입력: ";
cin >> num1 >> num2; //1. num2에 0이 입력되면 예외가 발생
if(num2==0)
{
cout << "제수는 0이 될 수 없습니다. " << endl; //2. 예외 발견
cout << "프로그램을 다시 실행하세요." << endl; //3. 예외처리 [다시 입력하라는 코드 출력]
}
else {
cout << "나눗셈의 몫: " << num1 / num2 << endl;
cout << "나눗셈의 나머지: " << num1 % num2 << endl;
}
return 0;
}
if문을 이용한 예외처리 [예외를 해결하는 방법이 아니라 다시 입력을 유도하는 코드 출력]
C++의 예외처리 메커니즘의 필요성 대두 : 예외처리와 일반적인 프로그램 흐름 구분을 위함
C++의 예외처리 메커니즘 [try~catch, throw]
#include <iostream>
using namespace std;
int main(void)
{
int num1, num2;
cout << "두 개의 숫자 입력: ";
cin >> num1 >> num2;
try {
if (num2 == 0)
throw num2; //try문에 항상 존재하진 않지만, throw 절이 실행이되면 try블록의 나머지 부분은 실행이 되지 않는다.
cout << "나눗셈의 몫: " << num1 / num2 << endl;
cout << "나눗셈의 나머지: " << num1 % num2 << endl;
} //예외와 연관이 있는 부분을 모두 하나의 try 블록으로 묶는다. [예외 발생시 실행되지 않도록]
catch (int expn)
{
cout << "제수는 " << expn << "이 될 수 없습니다." << endl;
cout << "프로그램을 다시 실행하세요." << endl;
}
cout << "end of main" << endl; //예외 발생하지 않으면 출력되는 문장
return 0;
}
try문의 예외 발생 검사범위를 지정하고 예외가 발생하면 throw절의 예외 데이터를 try문을 통해 catch로 전달한다.
catch문은 발생한 예외를처리하는 영역이며 반환형이 없는 함수처럼 정의되어있다.
try문과 catch문 사이에은 문장을 삽입할 수 없다.
스택풀기 -예외의 전달
#include<iostream>
using namespace std;
void Divide(int num1, int num2)
{
if (num2 == 0)
throw num2; //예외 데이터 전달 [throw절을 감싸는 try 블록이 존재하지 않는 경우]
cout << "나눗셈의 몫: " << num1 / num2 << endl;
cout << "나눗셈의 나머지: " << num1 & num2 << endl;
}
int main(void)
{
int num1, num2;
cout << "두 개의 숫자 입력: ";
cin >> num1 >> num2;
try {
Divide(num1, num2);
//함수 호출
cout << "나눗셈을 마쳤습니다." << endl;
}
catch (int expn)
{
cout << "제수는 " << expn << "이 될 수 없습니다." << endl;
cout << "프로그램을 다시 실행하세요." << endl;
}
return 0;
}
함수 내 예외 데이터 num2를 처리할 수 없다. -> 함수 호출한 영역으로 데이터를 전달한다.
예외가 처리되지 않으면, 예외가 발생한 함수를 호출한 영역으로
예외 데이터와 예외를 처리해야 하는 책임이 전달된다.
즉 throw의 예외 데이터는 반드시 처리되어야 한다.
예외의 발생 위치와 처리위치가 달라야 하는 경우
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int StoI(char* str)
{
int len = strlen(str);
int num = 0;
for (int i = 0; i < len; i++)
{
if (str[i] < '0' || str[i]> '9')
throw str[i];
num += (int)(pow((double)10, (len - 1) - i) * (str[i] + (7 - '7')));
}
return num;
}
int main(void)
{
char str1[100];
char str2[200];
while (1)
{
cout << "두 개의 숫자 입력: ";
cin >> str1 >> str2;
try
{
cout << str1 << "+" << str2 << "=" << StoI(str1) + StoI(str2) << endl;
break;
}
catch (char ch)
{
cout << "문자 " << ch << "가 입력되었습니다." << endl;
cout << "재입력 진행합니다." << endl << endl;
}
}
cout << "프로그램을 종료합니다." << endl;
return 0;
}
throw str[i];
예외의 데이터가 전달되면, 함수는 더이상 실행되지 않고 종료된다.
try
{
cout << str1 << "+" << str2 << "=" << StoI(str1) + StoI(str2) << endl;
break;
}
catch (char ch)
{
cout << "문자 " << ch << "가 입력되었습니다." << endl;
cout << "재입력 진행합니다." << endl << endl;
}
함수의 비정상 종료처리는 main에서
예외의 처리는 main에서 처리
스택풀기
#include<iostream>
using namespace std;
void SimpleFuncOne(void);
void SimpleFuncTwo(void);
void SimpleFuncThree(void);
int main(void)
{
try
{
SimpleFuncOne();
}
catch (int expn)
{
cout << "예외코드 : " << expn << endl;
}
return 0;
}
void SimpleFuncOne(void)
{
cout << "SimpleFuncOne(void)" << endl;
SimpleFuncTwo();
}
void SimpleFuncTwo(void)
{
cout << "SimpleFuncTwo(void)" << endl;
SimpleFuncThree();
}
void SimpleFuncThree(void)
{
cout << "SimpleFuncThree(void)" << endl;
throw - 1;
}
스택은 main -> SimpleFuncOne -> SimpleFuncTwo -> SimpleFuncThree 순으로 쌓이고
예외 데이터가 전달되면서 SimpleFuncThree -> SimpleFuncTwo -> SimpleFuncOne -> main 순으로 스택이 해제된다.
main함수에서조차 예외를 처리하지 않으면 terminate함수가 호출되면서 프로그램이 종료된다.
자료형이 일치하지 않아도 예외 데이터는 전달
int SimpleFunc(void)
{
try
{
if ()
throw - 1; //int형 예외데이터 발생
}
catch (char expn) //char형 예외데이터 전달
{
}
}
하나의 try 블록과 다수의 catch 블록
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
int StoI(char* str)
{
int len = strlen(str);
int num = 0;
if (len != 0 && str[0] == '0')
throw 0;
for (int i = 0; i < len; i++)
{
if (str[i] < '0' || str[i]> '9')
throw str[i];
num += (int)(pow((double)10, (len - 1) - i) * (str[i] + (7 - '7')));
}
return num;
}
int main(void)
{
char str1[100];
char str2[200];
while (1)
{
cout << "두 개의 숫자 입력: ";
cin >> str1 >> str2;
try
{
cout << str1 << "+" << str2 << "=" << StoI(str1) + StoI(str2) << endl;
break;
}
catch (char ch)
{
cout << "문자 " << ch << "가 입력되었습니다." << endl;
cout << "재입력 진행합니다." << endl << endl;
}
catch (int expn)
{
if (expn == 0)
cout << "0으로 시작하는 숫자는 입력불가." << endl;
else
cout << "비정상적 입력이 이루어졌습니다." << endl;
cout << "재입력 진행합니다." << endl << endl;
}
}
cout << "프로그램을 종료합니다." << endl;
return 0;
}
하나의 try 영역 내에서 종류가 다른 둘 이상의 예외발생 가능
-> 하나의 try블록에 다수의 catch 블록 추가 가능
전달되는 예외의 명시
int ThorwFunc(int num) throw(int, char)
//예외 상황 발생시 int형 예외 데이터, char형 예외 데이터 발생가능 명시
{
...
}
int형, char형 외 예외 데이터 전달시, terminate 함수 호출로 프로그램 종료 [대비못한 예외상황의 처리]
try
{
ThrowFunc(20);
}
catch(int expn){}
catch(char expn){}
int형 예외데이터와 char형 예외데이터의 처리
어떤 예외가 와도 프로그램 종료
int SimpleFunc(void) throw()
{
...
}
예외 상황을 표현하는 예외 클래스의 설계
#include <iostream>
#include <cstring>
using namespace std;
class DepositException
{
private:
int reqDep;
public:
DepositException(int money):reqDep(money)
{}
void ShowExceptionReason()
{
cout << "[예외메시지: " << reqDep << "는 입금불가]" << endl;
}
};
class WithdrawException
{
private:
int balance;
public:
WithdrawException(int money):balance(money)
{}
void ShowExcpetionReason()
{
cout << "[예외메시지: 잔액 " << balance << ", 잔액부족]" << endl;
}
};
class Account
{
private:
char accNum[50];
int balance;
public:
Account(const char* acc, int money) :balance(money)
{
strcpy_s(accNum, strlen(acc) + 1, acc);
}
void Deposit(int money) throw(DepositException)
{
if (money < 0)
{
DepositException expn(money);
throw expn; //객체 형태의 예외 데이터
}
balance += money;
}
void Withdraw(int money) throw (WithdrawException)
{
if (money > balance)
throw WithdrawException(balance); //임시객체의 형태로 전달 가능
balance -= money;
}
void ShowMyMoney()
{
cout << "잔고: " << balance << endl << endl;
}
};
int main(void)
{
Account myAcc("56789-827120", 5000);
try
{
myAcc.Deposit(2000);
myAcc.Deposit(-300);
}
catch (DepositException& expn)
{
expn.ShowExceptionReason(); //예외 객체의 멤버함수 호출
}
myAcc.ShowMyMoney();
try {
myAcc.Withdraw(3500);
myAcc.Withdraw(4500);
}
catch (WithdrawException& expn)
{
expn.ShowExcpetionReason(); //예외 객체의 멤버함수 호출
}
myAcc.ShowMyMoney();
return 0;
}
어떠한 유형의 에러인지 나타내기 위한 예외 클래스 [throw절에 오는 예외 객체를 생성한다.]
객체를 이용해 데이터와 행동을 나타낸다.
'Programming > C++ 3' 카테고리의 다른 글
[C++] 12-01. 대입연산자 오버로딩 (0) | 2021.05.30 |
---|---|
[C++] 10-01. 연산자 오버로딩의 이해와 유형 (0) | 2021.05.30 |
[C++] 09-02. 다중상속 (0) | 2021.05.30 |
[C++] 09-01. 멤버함수와 가상함수의 동작 원리 (0) | 2021.05.30 |
[C++] 08-03. 가상 소멸자 (0) | 2021.05.30 |