
주의 : 이 글은 C의 기초문법에 대해 상세하게 다루지 않습니다. (즉 C언어에서 배울 수 있는 기초내용은 생략합니다)
마지막장입니다. 이 다음 쳅터에서는 실무에서 꼭 필요한 개념 과 effective C++과 Morden C++의 책을 보면서 진행을 하도록 하겠습니다.
좋은 C++ 책들 + 레퍼런스들 - CPP 마이너 갤러리 (dcinside.com)
좋은 C++ 책들 + 레퍼런스들 - CPP 마이너 갤러리
좋은 C++ 책들 + 레퍼런스들원본 링크 : (https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)(본 글에는 번역본 링크만
gall.dcinside.com
이런 글도 있습니다. 참고가 될거 같습니다.
C++ 문서 - 시작, 자습서, 참조. | Microsoft Learn
C++ 문서 - 시작, 자습서, 참조.
Microsoft C++ 및 Visual Studio 사용자를 위한 C++ 프로그래밍 참조.
learn.microsoft.com
C++에서 예외처리와 오류처리방법이란?
프로그램을 짜면서 오류가 발생하는 이유는 무엇일까? 여기서 오류란 문법적인 문제가 아니라 코드가 돌면서 오류에 걸려 프로그램이 종료되는 상황을 이야기한다. 그래서 이런 실행오류의 원인은 크게 2가지가 있다고 볼 수 있는데
1. 개발자의 논리가 잘못된 경우 : 말 그래로 개발자가 논리를 잘못설계해서 오류가 나는 경우
2. 예외에 대한 대책을 준비하지 않은 경우 : 예를 들어서 정수를 입력해야하는데, 문자열을 입력하게 한 경우가 이에 해당한다고 볼 수 있다.
그래서 2번의 케이스를 대처하기 위해서는 조건문으로 거를 수도 있을 것이다.
예외와 예외처리
예외란 프로그램의 오동작이나 결과에 영향을 미치는 예상치 못한 상황 발생을 예외(exception)이라고 부른다. C++에서 예외처리는 순전히 소프트웨어로 구분할 수 있는 예외를 말한다.
이러한 예외처리의 기초는 try-throw-catch 이라고 볼 수 있다. 다른언어와는 조금 차이가 있다. 간단하게 예시를 하나 보자.
#include <iostream>
using namespace std;
int main() {
int x; cin >> x;
cout << 100 / x;
}
이 상황에서 0을 입력하면 컴파일러는 오류는 뱉는다.

0으로 나눌 수 없다. 그러면 지금의 상황을 한 번 예외처리 해보자.
#include <iostream>
using namespace std;
int main() {
int x; cin >> x;
try {
if (x == 0) {
throw 0;
}
cout << 100 / x;
}
catch(int x){
cout << "예외가 발생했습니다. " << x << "로 나누려 하고 있습니다.";
}
}
다음처럼 C++의 경우는 다른 언어와 다르다. 파이썬은 일단 오류가 나오면 except로 가서 실행을 한다.
integer = input("나눌 수 입력")
print(str(100/0))

그러면 그냥 try except만 걸면 끝난다.
try:
integer = input("나눌 수 입력")
print(str(100/0))
except:
print("나누기 실패")
근데 C++은 예외를 날려야하는 것으로 보인다. 그러면 우리도 그냥 예외를 날리지 말고 코드를 짜보자.

던져주어야만 처리가 되는 것으로 보인다..
C++은 왜이렇게 복잡하게 예외를 처리할까? 다음과 같은 경우라고 볼 수 있다. 하나의 try에 여러개의 catch가 들어올 수 있다.
"해당 코드는 실행이 안된다"
#include <iostream>
using namespace std;
int main() {
int x; cin >> x;
try {
if (x == 0) {
throw 0;
}
else if (x < 0) {
throw - 1;
}
cout << 100 / x;
}
catch(int x){
cout << "예외가 발생했습니다. " << x << "로 나누려 하고 있습니다.";
}
catch (int x) {
cout << "예외가 발생했습니다. 음수로 나누려 하고 있습니다.";
}
}
이는 catch에 동일하여 처리가 안된다.

그러면 어떻게 해야할까? 조금 이상하지만 매개변수를 변경해서 선언해야한다.
#include <iostream>
using namespace std;
int main() {
int x; cin >> x;
try {
if (x == 0) {
throw 0;
}
else if (x < 0) {
throw 1.1;
}
cout << 100 / x;
}
catch(int x){
cout << "예외가 발생했습니다. " << x << "로 나누려 하고 있습니다.";
}
catch (double x) {
cout << "예외가 발생했습니다. 음수로 나누려 하고 있습니다.";
}
}
다음처럼 진행하면 가능해진다, 아무래도 catch는 overloading 만 지원하는 것으로 보인다.
추가적으로 예외를 발생시키는 함수도 만들 수 있다.
#include <iostream>
using namespace std;
int division(int x ) throw(int, double){
if (x == 0) {
throw 0;
}
else if (x < 0) {
throw 1.1;
}
cout << 100 / x;
}
int main() {
int y; cin >> y;
try {
division(y);
}
catch (int x) {
cout << "예외가 발생했습니다. " << x << "로 나누려 하고 있습니다.";
}
catch (double x) {
cout << "예외가 발생했습니다. 음수로 나누려 하고 있습니다.";
}
}
특이사항으로는 catch는 함수에서 선언하는게 아니라, 함수에서는 예외를 리턴시키면 그걸 main문에서 받아서 처리한다.
추가적으로 try를 중첩시킬 수 있게 만들어져 있어서 다음처럼 코드를 작성할 수도 있다.
#include <iostream>
using namespace std;
void division(int x ) throw(int){
if (x == 0) {
throw 0;
}
cout << 100 / x;
}
void Hello(string hi) throw(int) {
if (hi != "안녕") {
throw 1.1;
}
cout << "인사를 받았습니다.";
}
int main() {
int y; cin >> y;
try {
try {
division(y);
}
catch (int x) {
cout << "예외가 발생했습니다. " << x << "로 나누려 하고 있습니다.";
}
cout << "안녕하세요";
string hi; cin >> hi;
Hello(hi);
}
catch (double y) {
cout << "너는 왜 인사 안받니?";
}
}
계산을 하고 안녕이라고 쳐주 않으면 인사를 받지 않는다고 출력이된다.
그럼 조금더 꼬아보자.

내부의 try에다가 1을 예외로 던저라 라는 코드가 들어있다면 어떤 catch가 실행될까?

위에 있는 catch 문이 실행된다. 그러면 이번엔 double을 주면?

난리가 난다.
예외 클래스
아까 위에서 보았을 때는 int랑 double로 해서 매개변수가 두가지로 catch 를 두가지 만들 수 있었으나 클래스가 있다면? 객체로 하면 되기 때문에 catch에서의 걱정이 사라진다.
그래서 부모 예외 클래스를 하나 선언하고, 자식클래스로 예외들을 정의하는 것이다. 다음을 한번 보도록하자.
#include <iostream>
using namespace std;
class myException {
string exception_name;
public:
myException(string exception_name) {
this->exception_name = exception_name;
}
void show_exception(){
cout << exception_name;
}
};
class DivideByZeroException : public myException {
public:
DivideByZeroException(string exception_name) : myException(exception_name){ }
};
int main() {
int x; cin >> x;
try {
if (x == 0) {
throw DivideByZeroException("0으로 나누려 합니다.");
}
cout << 100 / x;
}
catch (DivideByZeroException &e) {
e.show_exception();
}
}
최대한 쉽게 코드를 적었지만 난이도가 있을 수도 있다. 일단 부모클래스인 myException 은 exception_name이라는 멤버변수를 가지고 있다.
여튼 그의 자식클래스는 이제 객체가 생성될때 자신에게 입력된 내용으로 부모클래스의 생성자를 통해 생성한다.
내가 만약 0으로 나누려하면 이에 대한 exception을 객체로 던지게 된다. 객체로 던지면 객체에 대한 show_exception 메소를 실행해서 출력한다.
추가적인 내용으로 C++에서 C에서 돌릴 수 있게 링킹이라는 개념이 등장하는데, 이는 필요할 때 찾아서 쓰면 될 듯 싶다.
이제 실무 C++ 에서 만나도록 하자.
참고 문헌
Scott Douglas Meyers(2015). Effective C++. Protec Media(프로텍 미디어)
Robert C. Martin(2021).UML 실전에서는 이것만 쓴다(UML for Java Programmers). 인사이트
황기태(2021). 명품 C++ Programming. (주)생능출판사
'ㅇ 공부#언어 > (C++)기초' 카테고리의 다른 글
(기초 C++) 10장.템플릿과 STL(표준 템플릿 라이브러리) (0) | 2023.03.07 |
---|---|
(기초 C++) 9장. C++의 가상 함수와 추상 클래스 (0) | 2023.03.06 |
(기초 C++) 8장. C++에서의 클래스 상속 (0) | 2023.03.01 |
(기초 C++) 7장. C++에서의 프랜드와 연산자 중복 (0) | 2023.03.01 |
(기초 C++) 6장. C++에서의 함수 중복과 static 멤버 (0) | 2023.02.26 |