사용자 정의 예외 계층 구조
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 82번째.
표준 라이브러리는 std::runtime_error와 같은 유용한 예외 클래스를 제공하지만, 실제 애플리케이션에서는 사용자 지정 예외 계층 구조를 만드는 것이 유용한 경우가 많습니다. 표준 예외를 상속하는 자체 예외 클래스를 정의하면 추가적인 컨텍스트를 포함하고 더욱 정확한 오류 처리가 가능한 도메인별 오류 유형을 만들 수 있습니다.
사용자 정의 exception class는 일반적으로 std::exception 또는 그 파생 class 중 하나를 상속하고 what() 메서드를 재정의합니다:
#include <exception>
#include <string>
class DatabaseException : public std::exception {
std::string message;
public:
DatabaseException(const std::string& msg) : message(msg) {}
const char* what() const noexcept override { return message.c_str(); }
};
class ConnectionException : public DatabaseException {
public:
ConnectionException(const std::string& host)
: DatabaseException("Failed to connect to: " + host) {}
};
class QueryException : public DatabaseException {
public:
QueryException(const std::string& query)
: DatabaseException("Invalid query: " + query) {}
};이 계층 구조를 사용하면 catch 블록이 서로 다른 구체성 수준에서 예외를 처리할 수 있습니다:
try {
// 데이터베이스 작업...
throw ConnectionException("localhost");
} catch (const ConnectionException& e) {
std::cout << "Connection issue: " << e.what() << "\n";
} catch (const DatabaseException& e) {
std::cout << "Database error: " << e.what() << "\n";
} catch (const std::exception& e) {
std::cout << "General error: " << e.what() << "\n";
}noexcept 지정자는 what()에서 중요합니다. 이 지정자는 메서드가 예외를 발생시키지 않음을 보장하며, 이는 base 클래스 인터페이스에 필요합니다. C++에서는 첫 번째로 일치하는 핸들러를 사용하므로, catch 블록은 가장 구체적인 것부터 가장 일반적인 것 순서로 배치하세요.
챌린지
쉬움서로 다른 유형의 파일 관련 오류를 처리하는 사용자 지정 예외 계층 구조를 사용하여 파일 처리 시스템을 만들어 보겠습니다. 기본 예외 클래스에서 상속되는 도메인별 예외를 만들어 다양한 수준의 구체성에서 정밀한 오류 처리가 가능하도록 합니다.
코드를 세 개의 파일로 구성합니다:
FileExceptions.h: 파일 작업을 위한 사용자 지정 예외 계층 구조를 정의합니다.std::exception에서 상속되는 기본FileException클래스를 만듭니다. 이 클래스는 오류 메시지를 저장하고noexcept지정자를 사용하여what()메서드를 재정의해야 합니다.그런 다음 두 개의 파생 예외 클래스를 만듭니다:
FileNotFoundException: 파일 이름을 받아 메시지File not found: [filename]을 생성합니다.PermissionDeniedException: 파일 이름을 받아 메시지Permission denied: [filename]을 생성합니다.
각 파생 클래스는 적절한 메시지를 사용하여 부모 생성자를 호출해야 합니다.
FileProcessor.h: 파일 작업을 시뮬레이션하고 사용자 지정 예외를 발생시키는FileProcessor클래스를 정의합니다.FileProcessor에는 파일 열기를 시뮬레이션하는openFile(const std::string& filename)메서드가 있어야 합니다:- 파일 이름에
missing이 포함되어 있으면FileNotFoundException을 발생시킵니다. - 파일 이름에
locked가 포함되어 있으면PermissionDeniedException을 발생시킵니다. - 그렇지 않으면 문자열
Successfully opened: [filename]을 반환합니다.
- 파일 이름에
main.cpp: 입력에서 하나의 파일 이름을 읽습니다.FileProcessor를 만들고 파일 열기를 시도합니다. 가장 구체적인 핸들러부터 가장 일반적인 핸들러 순서로 구성된 try-catch 블록을 사용합니다:FileNotFoundException을 Catch하고File Error: [message]를 출력합니다.PermissionDeniedException을 Catch하고Access Error: [message]를 출력합니다.FileException을 Catch하고General File Error: [message]를 출력합니다.
예외가 발생하지 않으면
openFile()이 반환한 성공 메시지를 출력합니다.
예를 들어 입력이 report.txt인 경우:
Successfully opened: report.txt입력이 missing_data.csv인 경우:
File Error: File not found: missing_data.csv입력이 locked_config.ini인 경우:
Access Error: Permission denied: locked_config.ini이 챌린지는 사용자 지정 예외 계층 구조를 통해 적절한 세부 수준에서 오류를 처리하는 방법을 보여 줍니다. 정밀한 처리가 필요할 때는 구체적인 예외를 Catch하고, 모든 파일 오류를 일관되게 처리하려면 기본 예외를 Catch할 수 있습니다.
직접 해보기
#include <iostream>
#include <string>
#include "FileExceptions.h"
#include "FileProcessor.h"
using namespace std;
int main() {
string filename;
cin >> filename;
FileProcessor processor;
// TODO: 예외를 처리하기 위해 try-catch 블록을 사용하세요
// 핸들러를 가장 구체적인 것부터 가장 일반적인 것 순으로 정렬하세요:
// 1. FileNotFoundException을 catch - 출력: "File Error: [message]"
// 2. PermissionDeniedException을 catch - 출력: "Access Error: [message]"
// 3. FileException을 catch - 출력: "General File Error: [message]"
// 예외가 없으면 openFile()의 성공 메시지를 출력하세요
try {
// TODO: processor.openFile()을 호출하고 결과를 처리하세요
}
// TODO: 가장 구체적인 것부터 가장 일반적인 것 순으로 catch 블록을 추가하세요
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러